5

Ich habe mit einer Legacy-Datenbank zu tun, die Datums- und Uhrzeitfelder als char (8) -Spalten (formatiert JJJJMMTT bzw. HH: MM: SS) in einigen der Tabellen hat. Wie kann ich die 2 Char-Spalten einer einzelnen .NET DateTime-Eigenschaft zuordnen? Ich habe folgendes versucht, aber ich erhalte einen „nicht Setter Zugriff auf“ Fehler natürlich da Datetime Datum und TimeOfDay Eigenschaften schreibgeschützt sind:Wie ordnen Sie eine DateTime-Eigenschaft mit NHibernate (Fluent) 2 Varchar-Spalten in der Datenbank zu?

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"); 
      }); 

Ich habe auch versucht, einen IUserType für DateTime zu definieren, aber ich kann es nicht herausfinden. Ich habe eine Menge googeln für eine Antwort, aber ich kann es immer noch nicht herausfinden. Was ist meine beste Option, um diese dumme Legacy-Datenbank-Konvention zu behandeln? Ein Codebeispiel wäre hilfreich, da für einige dieser obskuren Szenarien nicht viel Dokumentation vorhanden ist.

Antwort

8

Sie benötigen einen ICompositeUserType, um mehr als eine Spalte zu behandeln. Sie müssen die Fehlerprüfung, das Parsen von Formaten usw. verbessern, aber hier ist ein Ausgangspunkt für Sie.

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; } } 

} 

=== fließend Mapping (vorausgesetzt, Automapping w/Override-Klassen) ====

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

Was wäre die Zuordnung für diese aussehen? Ich habe einige IUserType-Implementierungen erstellt, aber immer für einzelne Eigenschaften/Spaltenpaare. Ich habe mich gefragt, in welchen Szenarien das 'names' Array mehr als ein Element haben würde. –

+0

Hallo Jamie. Sie müssen die Eigenschaft nur dem benutzerdefinierten Typ zuordnen. In FNH würde es so einfach aussehen wie die Codezeile, die ich am Ende zu meinem Post hinzugefügt habe. Wenn der benutzerdefinierte Typ allgegenwärtig ist, können Sie auch eine Konvention einrichten, um damit umzugehen. Prost – Berryl

+0

das sieht hervorragend aus! Danke viel! Ich werde es versuchen, wenn ich später zur Arbeit komme und dies als Antwort basierend auf meinen Tests setzen. – gabe

Verwandte Themen