2010-03-25 57 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