NHibernate IUserType将可为空的日期时间转换为DB not null值
我有一个遗留数据库存储日期,这意味着没有日期为9999-21-31, 列NHibernate IUserType将可为空的日期时间转换为DB not null值,nhibernate,nullable,Nhibernate,Nullable,我有一个遗留数据库存储日期,这意味着没有日期为9999-21-31, 列Till_Date的类型为DateTimenotnull=“true” 在应用程序中,我要构建持久化类,该类不将任何日期表示为null, 所以我在C#//public DateTime中使用了null DateTime?TillDate{get;set;} 我创建了IUserType,它知道如何将实体空值转换为DB 9999-12-31 但NHibernate似乎没有在我的IUserType上调用SafeNullGet和Sa
Till_Date
的类型为DateTimenotnull=“true”
在应用程序中,我要构建持久化类,该类不将任何日期表示为null,
所以我在C#//public DateTime中使用了null DateTime?TillDate{get;set;}
我创建了IUserType,它知道如何将实体空值转换为DB 9999-12-31
但NHibernate似乎没有在我的IUserType上调用SafeNullGet和SafeNullSet
当实体值为null,并且报告null用于not null列时
我试图通过将列映射为notnull=“false”来绕过它
(仅更改了映射文件,未更改数据库)
但它仍然没有帮助,只是现在它尝试将null值插入数据库并获取ADOException
如果NHibernate不支持将null值转换为NOTNULL值的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; }
}
}
}
问题可能出现在
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实现看起来是正确的 通过调试,我看到对equals的调用为两个比较的值传递null。我尝试了两个版本的Equals,关于这一点:如果比较值为null,则第一次返回true;如果比较值为null,则第二次返回false。如果比较值为null,请参阅添加的代码实现tnxI根据您的代码调整内容(在NullSafeGet中添加显式强制转换),它可以工作,但在以下情况下除外,如果在DB中,日期不是最大值(例如2010-01-01)我获取实体,将日期更改为null并保存更改,然后它调用Equals(2010-01-01,null),返回false,但不调用NullSafeSet并引发异常:NHibernate.PropertyValueException:notnull属性引用null或暂时值。然后,我在hbm.xml中将映射更改为notnull=“false”,这次调用了NullSafeSet。谢谢你的帮助,我有点惊讶NOTNULL设置会影响这一点,我认为这只是用于模式生成。如果答案有帮助,请投票并接受。结果证明问题仍然存在。但只有当您尝试在DateTime中持久化具有空值的新瞬态实体时才会发生这种情况?财产。但当更新已持久化的实体时,它工作正常。我能够找到原因,我的类映射xml具有dynamic insert=“true”。将其更改为false后,所有操作正常。(我也有dynamic update=“true”,但一切正常)在属性映射中没有null=“true”的P.S仍然失败。我需要可为null的DB-DATE类型。所以我用DateTime.MinValue替换了MaxDate,它可以正常工作