简体   繁体   English

NHibernate IUserType 未应用于插入

[英]NHibernate IUserType not being applied on Insert

I'm using NHibernate with Postgresql as the backend and had to create custom types for converting System.DateTime to Postgresql "time" types as well as System.TimeSpans to "interval" db types.我正在使用 NHibernate 和 Postgresql 作为后端,并且必须创建自定义类型来将 System.DateTime 转换为 Postgresql 到“时间”类型以及 System.TimeSpansdb 类型The IUserType I created are working and are being applied for reads and updates but they are never being applied when I try to insert an object into the database.我创建的 IUserType 正在工作并且正在应用于读取和更新,但是当我尝试将 object 插入数据库时,它们从未被应用。 I've set breakpoints in the IUserTypes but they never are hit when an insert is happening.我在 IUserTypes 中设置了断点,但是当插入发生时它们永远不会被击中。

I think the issue may be around the fact that the object is just a POCO object and isn't a proxy yet so the mapping that applies the transformation to the usertype doesn't happen when I set the value of my property.我认为问题可能在于 object 只是 POCO object 并且还不是代理,因此当我设置我的属性值时,不会发生将转换应用于用户类型的映射。

If I do an update and set one of these properties I can see the breakpoints in the IUserType are fired.如果我进行更新并设置这些属性之一,我可以看到 IUserType 中的断点被触发。

Any thoughts?有什么想法吗?

UPDATE The Equals Method of the IUserType is being called but the NullSafeSet where I do the necessary conversion is not.更新IUserType 的 Equals 方法被调用,但我进行必要转换的 NullSafeSet 不是。

EDIT Added code samples编辑添加的代码示例

    public class TimeType : BaseImmutableUserType<TimeSpan>
    {
        public override object NullSafeGet(IDataReader rs, string[] names, object owner)
        {
            var val = NHibernateUtil.Time.NullSafeGet(rs, names[0]);
            if (val == null)
                return null;

            var dt = DateTime.Parse(val.ToString());

            return new TimeSpan(0, dt.Hour, dt.Minute, dt.Second);
        }

        public override void NullSafeSet(IDbCommand cmd, object value, int index)
        {
            var obj = (TimeSpan)value;

            ((IDbDataParameter) cmd.Parameters[index]).Value = obj;
        }

        public override SqlType[] SqlTypes
        {
            get
            {
                return new[] { SqlTypeFactory.Time };
            }
        }
    }

    public abstract class BaseImmutableUserType<T> : IUserType
    {
        public abstract object NullSafeGet(IDataReader rs, string[] names, object owner);
        public abstract void NullSafeSet(IDbCommand cmd, object value, int index);
        public abstract SqlType[] SqlTypes { get; }

        public BaseImmutableUserType()
        {
            int i = 0;
        }

        public new bool Equals(object x, object y)
        {
            if (ReferenceEquals(x, y))
            {
                return true;
            }

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

            return x.Equals(y);
        }

        public int GetHashCode(object x)
        {
            return x.GetHashCode();
        }

        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 DeepCopy(cached);
        }

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

        public Type ReturnedType
        {
            get { return typeof(T); }
        }

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

I found the following two options:我找到了以下两个选项:

Option 1: do not use your own UserType.选项 1:不要使用您自己的 UserType。 Instead use NHibernate's own TimeAsTimeSpan like this:而是像这样使用 NHibernate 自己的 TimeAsTimeSpan:

Map(x => x.TimeFrom)
    .CustomType("TimeAsTimeSpan");

(Example taken from here ) (示例取自这里

Option 2: Modify your class a little:选项 2:稍微修改您的 class :

public class TimeType : BaseImmutableUserType<TimeSpan>
{
    // this is taken from the source of NHibernate.Type.TimeAsTimeSpanType
    private static readonly DateTime BaseDateValue = new DateTime(1753, 01, 01);

    public override object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        var val = NHibernateUtil.TimeAsTimeSpan.NullSafeGet(rs, names[0]);
        if (val == null)
            return null;

        var dt = DateTime.Parse(val.ToString());

        return new TimeSpan(0, dt.Hour, dt.Minute, dt.Second);
    }

    public override void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        //var obj = (TimeSpan)value;  // we can't use TimeSpan here but need to use DateTime
        // this is taken from the source of NHibernate.Type.TimeAsTimeSpanType
        DateTime date = BaseDateValue.AddTicks(((TimeSpan)value).Ticks);
        ((IDbDataParameter)cmd.Parameters[index]).Value = date;
    }

    public override SqlType[] SqlTypes
    {
        get
        {
            return new[] { NHibernate.SqlTypes.SqlTypeFactory.Time };
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM