2009-07-27 15 views
9

Tengo un objeto de modelo de dominio que tiene propiedades de tipo System.DateTimeOffset. Estoy usando una base de datos que no admite este tipo de forma nativa, por lo que estoy planeando almacenarlo usando una columna de tipo 'datetime' y una de tipo 'smallint'.Uso de NHibernate ICompositeUserType con un tipo de valor

He estado buscando cómo mapear esto usando los componentes de NHibernate, y encontré que podría funcionar usando una instancia de ICompositeUserType. Sin embargo, al implementar la interfaz, me encontré con el método llamado "SetPropertyValue" que ostensiblemente establece una propiedad dentro del tipo. Como DateTimeOffset es un System.ValueType, el solo hecho de configurar una propiedad como esta no funcionará, ya que es inmutable (al menos, sin utilizar algún reflejo o código inseguro, que me gustaría evitar). Como el parámetro de instancia en SetPropertyValue no es 'ref', ¿cómo se usan instancias de ValueType como componentes en NHibernate?

Respuesta

6

Haga que el tipo de usuario sea inmutable devolviendo el valor falso en IsMutable y genere una excepción en SetPropertyValue.

Tengo algo similar, pero con un tipo de datos propio en lugar de DateTimeOffset. Acabo de adaptar el código para ti. Almacena la fecha como hora UTC y la compensación como TimeSpan (almacena Ticks. Por supuesto que no necesita esta resolución. Pero, no debe almacenar horas completas para zonas horarias, hay desplazamientos de zonas horarias con fracciones de horas! ! Y TimeSpan es construir en un trabajo fuera de la caja.)

public class DateTimeOffsetUserType : ICompositeUserType 
{ 
    public bool IsMutable 
    { 
     get { return false; } 
    } 

    public void SetPropertyValue(object component, int property, object value) 
    { 
     throw new InvalidOperationException("Immutable, SetPropertyValue is not allowed"); 
    } 

    public object NullSafeGet(System.Data.IDataReader dr, string[] names, NHibernate.Engine.ISessionImplementor session, object owner) 
    { 
     if (dr == null) 
     { 
      return null; 
     } 

     DateTime? utcTime; 
     TimeSpan? offset; 

     utcTime = (DateTime?)PropertyTypes[0].NullSafeGet(dr, names[0], session, owner); 
     offset = (TimeSpan?)PropertyTypes[1].NullSafeGet(dr, names[1], session, owner); 

     if (utcTime == null || offset == null) return null; 
     return new DateTimeOffset(utcTime.Value, offset.Value); 
    } 

    public void NullSafeSet(System.Data.IDbCommand cmd, object value, int index, NHibernate.Engine.ISessionImplementor session) 
    { 
     if (value == null) 
     { 
      NHibernateUtil.Timestamp.NullSafeSet(cmd, null, index); 
      NHibernateUtil.TimeSpan.NullSafeSet(cmd, null, index + 1); 
     } 
     else 
     { 
      DateTimeOffset dateTimeOffset = (DateTimeOffset)value; 

      PropertyTypes[0].NullSafeSet(cmd, dateTimeOffset.UtcDateTime, index, session); 
      PropertyTypes[1].NullSafeSet(cmd, dateTimeOffset.Offset, index + 1, session); 
     } 

    } 

    // other methods 
0
public void SetPropertyValue(object component, int property, object value) 

Tengo un código que implementa DateTime desde dos campos int.

El código es esencialmente una propiedad de cambio (0 es la fecha, 1 es el tiempo, en mi caso) y al final de cada declaración de caso, el objeto componente se reasigna a una nueva instancia de DateTime.

propiedad = 0 (Fecha):

// code to calculate year, month, day from object value 
DateTime dt = (DateTime)component; 
dt = new DateTime(year, month, day, dt.Hour, dt.Minute, dt.Second); 

propiedad = 1 (Tiempo):

// code to calculate hours, minutes, seconds from object value 
DateTime dt = (DateTime)component; 
dt = new DateTime(dt.Year, dt.Month, dt.Day, hours, minutes, seconds); 

ni idea de si esto es bueno/malo, pero funciona para mí (también conocido como tengo no hay problema cambiando a qué componente apunta, ref o no).

+0

Ok, es suficiente ... Estoy siguiendo hasta ahora. ¿Pero cómo vuelve su instancia 'dt' al modelo de dominio? – codekaizen

+0

dt = component, acaba de convertir a DateTime. Podría reemplazarlo en todas partes con el componente ((DateTime)). El componente es lo que realmente se devuelve al modelo de dominio. – anonymous

+0

No estoy seguro de si hay documentación de esto. Ni siquiera lo recuerdo y tuve que mirar el contexto en mi código. Creo que tuve que mirar el ejemplo que normalmente se proporciona con NHibernate (¿twostrings, creo?) Y aprender de eso (y obviamente olvidarlo una vez que haya terminado!) – anonymous

2

Tengo entendido que si el tipo que está mapeando e ICompositeUserType es inmutable, SetPropertyValue() no debería hacer nada en absoluto, o incluso lanzar una excepción, ya que nhibernate no debería llamarlo.

Cuestiones relacionadas