将NHibernate ICompositeUserType与值类型一起使用

时间:2009-07-27 17:12:07

标签: nhibernate orm value-type

我有一个域模型对象,其属性类型为System.DateTimeOffset。我正在使用一个本地不支持这种类型的数据库,所以我打算使用'datetime'类型的列和'smallint'类型的列来存储它。

我已经研究过如何使用NHibernate组件映射它,并发现它可以使用ICompositeUserType实例。但是,在实现接口时,我遇到了名为“SetPropertyValue”的方法,该方法表面上设置了类型中的属性。由于DateTimeOffset是一个System.ValueType,只是设置这样的属性是不可行的,因为它是不可变的(至少,没有使用一些反射或不安全的代码,我想避免)。由于SetPropertyValue上的实例参数不是'ref',如何在NHibernate中使用ValueType实例作为组件?

3 个答案:

答案 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);

不知道这是好还是坏,但它适用于我(也就是我没有问题,改变哪个组件指向,参考或不参与)。