5

Estoy tratando con una base de datos heredada que tiene campos de fecha y hora como columnas char (8) (formateadas aaaaMMdd y HH: mm: ss, respectivamente) en algunas de las tablas. ¿Cómo puedo asignar las 2 columnas de caracteres a una única propiedad .NET DateTime? He intentado lo siguiente, pero me sale un error "no se puede acceder a la moda", por supuesto, porque DateTime Fecha y TimeOfDay propiedades son de sólo lectura:¿Cómo se asigna una propiedad DateTime a 2 columnas varchar en la base de datos con NHibernate (Fluido)?

public class SweetPocoMannaFromHeaven 
{  
    public virtual DateTime? FileCreationDateTime { get; set; } 
} 

.

mapping.Component<DateTime?>(x => x.FileCreationDateTime, 
      dt => 
      { 
       dt.Map(x => x.Value.Date, 
        "file_creation_date"); 
       dt.Map(x => x.Value.TimeOfDay, 
        "file_creation_time"); 
      }); 

También he intentado definir un IUserType para DateTime, pero no puedo resolverlo. He buscado mucho en Google para encontrar una respuesta, pero aún no lo puedo descifrar. ¿Cuál es mi mejor opción para manejar esta estúpida convención de base de datos heredada ? Un ejemplo de código sería útil ya que no hay mucha información sobre algunos de estos escenarios más oscuros.

Respuesta

8

Necesita un ICompositeUserType para manejar más de una columna. Necesita reforzar la comprobación de errores, los formatos de análisis, etc., pero este es un punto de partida para usted.

HTH,
Berryl

public class LegacyDateUserType : ICompositeUserType 
{ 

    public new bool Equals(object x, object y) 
    { 
     if (x == null || y == null) return false; 
     return ReferenceEquals(x, y) || x.Equals(y); 
    } 

    public int GetHashCode(object x) { 
     return x == null ? typeof (DateTime).GetHashCode() + 473 : x.GetHashCode(); 
    } 

    public object NullSafeGet(IDataReader dr, string[] names, ISessionImplementor session, object owner) 
    { 
     if (dr == null) return null; 

     var datePortion = NHibernateUtil.String.NullSafeGet(dr, names[0], session, owner) as string; 
     var timePortion = NHibernateUtil.String.NullSafeGet(dr, names[1], session, owner) as string; 

     var date = DateTime.Parse(datePortion); 
     var time = DateTime.Parse(timePortion); 
     return date.AddTicks(time.Ticks); 
    } 

    ///<summary> 
    /// Write an instance of the mapped class to a prepared statement. Implementors 
    /// should handle possibility of null values. A multi-column type should be written 
    /// to parameters starting from index. 
    ///</summary> 
    public void NullSafeSet(IDbCommand cmd, object value, int index, ISessionImplementor session) { 
     if (value == null) { 
      // whatever 
     } 
     else { 
      var date = (DateTime) value; 
      var datePortion = date.ToString("your date format"); 
      NHibernateUtil.String.NullSafeSet(cmd, datePortion, index, session); 
      var timePortion = date.ToString("your time format"); 
      NHibernateUtil.String.NullSafeSet(cmd, timePortion, index + 1, session); 
     } 
    } 

    public object GetPropertyValue(object component, int property) 
    { 
     var date = (DateTime)component; 
     return property == 0 ? date.ToString("your date format") : date.ToString("your time format"); 
    } 

    public void SetPropertyValue(object component, int property, object value) 
    { 
     throw new NotSupportedException("DateTime is an immutable object."); 
    } 

    public object DeepCopy(object value) { return value; } 

    public object Disassemble(object value, ISessionImplementor session) { return value; } 

    public object Assemble(object cached, ISessionImplementor session, object owner) { return cached; } 

    public object Replace(object original, object target, ISessionImplementor session, object owner) { return original; } 

    ///<summary>Get the "property names" that may be used in a query.</summary> 
    public string[] PropertyNames { get { return new[] { "DATE_PORTION", "TIME_PORTION" }; } } 

    ///<summary>Get the corresponding "property types"</summary> 
    public IType[] PropertyTypes { get { return new IType[] { NHibernateUtil.String, NHibernateUtil.String }; } } 

    ///<summary>The class returned by NullSafeGet().</summary> 
    public Type ReturnedClass { get { return typeof(DateTime); } } 

    ///<summary>Are objects of this type mutable?</summary> 
    public bool IsMutable { get { return false; } } 

} 

=== mapeo fluidez (automapping suponiendo w/clases de anular) ====

public void Override(AutoMapping<MyClass> m) 
{ 
    .... 
    m.Map(x => x.MyDateTime).CustomType<LegacyDateUserType>(); 
} 
+1

¿Cómo sería el mapeo de este parecería? He creado algunas implementaciones de IUserType, pero siempre para pares de propiedades individuales/columnas. Me he preguntado en qué escenarios la matriz 'names' tendría más de un elemento. –

+0

Hola Jamie. Solo necesita asociar la propiedad al tipo personalizado; en FNH parecería tan simple como la línea de código que agregué al final de mi publicación. Si el tipo personalizado era generalizado, podría establecer una convención para tratarlo también. Cheers – Berryl

+0

esto se ve excelente! ¡mucho! Lo intentaré cuando llegue a trabajar más tarde y lo estableceré como una respuesta basada en mis pruebas. – gabe

Cuestiones relacionadas