我有一个域模型对象,其属性类型为System.DateTimeOffset。我正在使用一个本地不支持这种类型的数据库,所以我打算使用'datetime'类型的列和'smallint'类型的列来存储它。
我已经研究过如何使用NHibernate组件映射它,并发现它可以使用ICompositeUserType实例。但是,在实现接口时,我遇到了名为“SetPropertyValue”的方法,该方法表面上设置了类型中的属性。由于DateTimeOffset是一个System.ValueType,只是设置这样的属性是不可行的,因为它是不可变的(至少,没有使用一些反射或不安全的代码,我想避免)。由于SetPropertyValue上的实例参数不是'ref',如何在NHibernate中使用ValueType实例作为组件?
答案 0 :(得分:6)
通过在IsMutable
中返回false,使用户输入为immutable,并在SetPropertyValue
中抛出异常。
我有类似的东西,但有自己的数据类型而不是DateTimeOffset
。我刚刚为你调整了代码。它将日期存储为UTC时间,偏移量存储为TimeSpan
(存储Ticks。当然,您不需要此分辨率。但是,您不应存储整个时区的时区,时区偏移几小时 !! TimeSpan
开箱即用。{/ p>
public class DateTimeOffsetUserType : ICompositeUserType
{
public bool IsMutable
{
get { return false; }
}
public void SetPropertyValue(object component, int property, object value)
{
throw new InvalidOperationException("Immutable, SetPropertyValue is not allowed");
}
public object NullSafeGet(System.Data.IDataReader dr, string[] names, NHibernate.Engine.ISessionImplementor session, object owner)
{
if (dr == null)
{
return null;
}
DateTime? utcTime;
TimeSpan? offset;
utcTime = (DateTime?)PropertyTypes[0].NullSafeGet(dr, names[0], session, owner);
offset = (TimeSpan?)PropertyTypes[1].NullSafeGet(dr, names[1], session, owner);
if (utcTime == null || offset == null) return null;
return new DateTimeOffset(utcTime.Value, offset.Value);
}
public void NullSafeSet(System.Data.IDbCommand cmd, object value, int index, NHibernate.Engine.ISessionImplementor session)
{
if (value == null)
{
NHibernateUtil.Timestamp.NullSafeSet(cmd, null, index);
NHibernateUtil.TimeSpan.NullSafeSet(cmd, null, index + 1);
}
else
{
DateTimeOffset dateTimeOffset = (DateTimeOffset)value;
PropertyTypes[0].NullSafeSet(cmd, dateTimeOffset.UtcDateTime, index, session);
PropertyTypes[1].NullSafeSet(cmd, dateTimeOffset.Offset, index + 1, session);
}
}
// other methods
答案 1 :(得分:2)
我的理解是,如果您要映射的类型和ICompositeUserType是不可变的,SetPropertyValue()应该什么也不做,甚至抛出异常,因为nhibernate不应该调用它。
答案 2 :(得分:0)
public void SetPropertyValue(object component, int property, object value)
我有从两个int字段实现DateTime的代码。
代码本质上是一个开启属性(0表示日期,1表示时间,在我的情况下),并且在每个case语句的末尾,组件对象被重新分配一个新的DateTime实例。
property = 0(Date):
// code to calculate year, month, day from object value
DateTime dt = (DateTime)component;
dt = new DateTime(year, month, day, dt.Hour, dt.Minute, dt.Second);
property = 1(时间):
// code to calculate hours, minutes, seconds from object value
DateTime dt = (DateTime)component;
dt = new DateTime(dt.Year, dt.Month, dt.Day, hours, minutes, seconds);
不知道这是好还是坏,但它适用于我(也就是我没有问题,改变哪个组件指向,参考或不参与)。