5

Je traite une base de données héritée qui contient des champs de date et d'heure sous forme de colonnes char (8) (formaté aaaaMMjj et HH: mm: ss, respectivement) dans certaines tables. Comment puis-je mapper les 2 colonnes char à une seule propriété .NET DateTime? J'ai essayé ce qui suit, mais je reçois une erreur « ne peut pas accéder setter » bien sûr parce que les propriétés DateTime Date et timeofday sont en lecture seule:Comment mapper une propriété DateTime à 2 colonnes varchar dans la base de données avec NHibernate (Fluent)?

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

. J'ai également essayé de définir un IUserType pour DateTime, mais je ne peux pas le comprendre. J'ai fait une tonne de googling pour une réponse, mais je ne peux pas comprendre encore. Quelle est ma meilleure option pour gérer cette convention de base de données stupide ? Un exemple de code serait utile car il n'y a pas beaucoup de documentation sur certains de ces scénarios plus obscurs.

Répondre

8

Vous avez besoin d'un ICompositeUserType pour gérer plusieurs colonnes. Vous devez renforcer la vérification des erreurs, les formats d'analyse, etc, mais voici un point de départ pour vous.

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

} 

=== mapping courant (en supposant AutoMapping w/classes) override de ====

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

Qu'est-ce que le mappage pour cela ressemble? J'ai créé quelques imnplementations IUserType mais toujours pour des paires de propriétés/colonnes uniques. Je me suis demandé dans quels scénarios le tableau 'names' aurait plus d'un élément. –

+0

Bonjour Jamie. Vous avez juste besoin d'associer la propriété au type personnalisé; dans FNH, il semblerait aussi simple que la ligne de code ajoutée à la fin de mon article. Si le type personnalisé était répandu, vous pourriez mettre en place une convention pour y faire face également. Bravo – Berryl

+0

cela semble excellent! Merci beaucoup! Je vais essayer quand je vais travailler plus tard et mettre cela comme réponse en fonction de mes tests. – gabe