2010-03-25 59 views
3

我有一個存儲日期傳統DB這意味着無日期9999-21-31, 列Till_Date是DateTime類型not-null="true"的。NHibernate的IUserType轉換爲空的日期時間到DB不是空值

在應用程序中,我想構建持久化類,它表示無日期爲空, 因此,我在C#// public DateTime中使用了可空的DateTime? TillDate {get;組; }

我創建IUserType,知道的實體空值轉換爲DB 9999-12-31

但似乎NHibernate的不叫SafeNullGet,SafeNullSet我IUserType 當實體值爲空,並且報告null用於非空列。

我試圖通過映射列不空=「假」 (只更改了映射文件,而不是DB) ,但它仍然沒有幫助繞過它,只是現在它試圖插入將空值賦給數據庫並獲取ADOException。

任何知識,如果NHibernate不支持IUseType將空值轉換爲非空值?

//在需要修復之前執行!!!

public class NullableDateTimeToNotNullUserType : IUserType 
{ 
     private static readonly DateTime MaxDate = new DateTime(9999, 12, 31); 

     public new bool Equals(object x, object y) 
     {             //This didn't work as well 
      if (ReferenceEquals(x, y)) return true; //if(x == null && y == null) return false; 

      if (x == null || y == null) return false; 

      return x.Equals(y); 
     } 

     public int GetHashCode(object x) 
     { 
      return x == null ? 0 : x.GetHashCode(); 
     } 

     public object NullSafeGet(IDataReader rs, string[] names, object owner) 
     { 
      var value = rs.GetDateTime(rs.GetOrdinal(names[0])); 

      return (value == MaxDate)? null : value; 
     } 

     public void NullSafeSet(IDbCommand cmd, object value, int index) 
     { 
      var dateValue = (DateTime?)value; 

      var dbValue = (dateValue.HasValue) ? dateValue.Value : MaxDate; 

      ((IDataParameter)cmd.Parameters[index]).Value = dbValue; 
     } 

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

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

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

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

     public SqlType[] SqlTypes 
     { 
      get { return new[] { NHibernateUtil.DateTime.SqlType }; } 
     } 

     public Type ReturnedType 
     { 
      get { return typeof(DateTime?); } 
     } 

     public bool IsMutable 
     { 
      get { return false; } 
     } 
    } 
} 

//最終實施與修復。

//Make the column mapping in hbm.xml not-null="false" even if in DB null not allowed. 
//Make sure the class mapping in xml doesn't have dynamic-insert="true" 

public class NullableDateTimeToNotNullUserType : IUserType 
{ 
     private static readonly DateTime MaxDate = new DateTime(9999, 12, 31); 

     public new bool Equals(object x, object y) 
     {             //This didn't work as well 
      if (ReferenceEquals(x, y)) return true; //if(x == null && y == null) return false; 

      if (x == null || y == null) return false; 

      return x.Equals(y); 
     } 

     public int GetHashCode(object x) 
     { 
      return x == null ? 0 : x.GetHashCode(); 
     } 

     public object NullSafeGet(IDataReader rs, string[] names, object owner) 
     { 
      var value = NHibernateUtil.Date.NullSafeGet(rs, names[0]); 

      return (value == MaxDate)? default(DateTime?) : value; 
     } 

     public void NullSafeSet(IDbCommand cmd, object value, int index) 
     { 
      var dateValue = (DateTime?)value; 

      var dbValue = (dateValue.HasValue) ? dateValue.Value : MaxDate; 

      NHibernateUtil.Date.NullSafeSet(cmd, valueToSet, index); 
     } 

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

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

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

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

     public SqlType[] SqlTypes 
     { 
      get { return new[] { NHibernateUtil.DateTime.SqlType }; } 
     } 

     public Type ReturnedType 
     { 
      get { return typeof(DateTime?); } 
     } 

     public bool IsMutable 
     { 
      get { return false; } 
     } 
    } 
} 

回答

1

的問題很可能在你的實現Equals。 NHibernate使用Equals來確定它是否需要獲取或設置值。請發佈您的IUserType實現。

編輯:好的,我想我看到了問題。試試這個:

public object NullSafeGet(IDataReader rs, string[] names, object owner) 
{ 
    var value = NHibernateUtil.Date.NullSafeGet(rs, names[0]); 
    return (value == MaxDate) ? null : value; 
} 

public void NullSafeSet(IDbCommand cmd, object value, int index) 
{ 
    var dateValue = (DateTime?)value; 
    var dbValue = (dateValue.HasValue) ? dateValue.Value : MaxDate; 
    NHibernateUtil.Date.NullSafeSet(cmd, valueToSet, index); 
} 

NullSafeGet可能還需要將返回值轉換爲DateTime ?. Equals的實現看起來是正確的。

+0

使用調試我看到對等值的調用傳遞兩個比較值爲null。 我試過2個版本的Equals的,就認爲: 1日返回true,如果比較的值都爲空 2日返回false,如果比較的值都爲空 請參閱添加的代碼執行 TNX – barakbbn 2010-03-25 21:12:52

+0

我根據你的代碼調整的事情(添加顯式轉換在NullSafeGet) 它的工作原理,除了在下列情況下, 如果在DB的日期是不是最大(例如,2010-01-01) ,我取的實體,更改日期爲空並保存更改,然後 它會調用返回false的Equals(2010-01-01,null), 但不調用NullSafeSet並拋出以下異常: NHibernate.PropertyVa lueException:非空屬性引用空值或瞬態值。 然後,我在hbm.xml中將映射更改爲not-null =「false」,並且它在這次調用了NullSafeSet。 感謝您的幫助 – barakbbn 2010-03-26 15:52:09

+0

我有點驚訝,非空設置會影響到這一點,我認爲這隻適用於模式生成。如果有幫助,請注意並接受答案。 – 2010-03-26 16:01:34