【问题标题】:How can I use NHibernate with immutable type like System.Tuple?如何将 NHibernate 与 System.Tuple 等不可变类型一起使用?
【发布时间】:2012-07-04 11:18:23
【问题描述】:

我有一个使用System.Tuple<int,string> 的复合映射,如下所示:

<composite-element
  class="System.Tuple`2[[System.Int32, mscorlib],[System.String, mscorlib]], mscorlib">
    <property name="Item1" column="DBColumn1"/>
    <property name="Item2" column="DBColumn2"/>
</composite-element>

我尝试搞乱BytecodeProviderIObjectsFactoryReflectionOptimizer 等等,但我无法让 NHibernate 正确加载我的元组(无论我做什么,NHibernate 都坚持首先创建对象并填充值稍后出)。

NHibernate 能否以某种方式强制正确加载和持久化不可变类型?

【问题讨论】:

    标签: .net nhibernate nhibernate-mapping tuples immutability


    【解决方案1】:

    你试过ICompositeUserType吗?它将允许您为 Tuple&lt;int, string&gt; 属性定义这样的映射:

    <property name="MyProperty" type="MyNamespace.TupleIntStringType, MyAssembly">
        <column name="Item1"/>
        <column name="Item2"/>
    </property>
    

    自定义类型定义为:

    public class TupleIntStringType : ICompositeUserType
    {
        public object GetPropertyValue(object component, int property)
        {
            var tuple = (Tuple<int, string>)component;
            switch (property)
            {
                case 0:
                    return tuple.Item1;
                case 1:
                    return tuple.Item2;
                default:
                    throw new InvalidOperationException(String.Format("No property number {0} found", property));
            }
        }
    
        public void SetPropertyValue(object component, int property, object value)
        {
            throw new InvalidOperationException("Immutable, SetPropertyValue is not allowed");
        }
    
        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 == null ? 0 : x.GetHashCode();
        }
    
        public object NullSafeGet(IDataReader dr, string[] names, ISessionImplementor session, object owner)
        {
            var item1 = (int)PropertyTypes[0].NullSafeGet(dr, names[0], session, owner);
            var item2 = (String)PropertyTypes[1].NullSafeGet(dr, names[1], session, owner);
    
            return Tuple.Create(item1, item2);
        }
    
        public void NullSafeSet(IDbCommand cmd, object value, int index, bool[] settable, ISessionImplementor session)
        {
            if (value == null)
            {
                NHibernateUtil.Timestamp.NullSafeSet(cmd, null, index);
                NHibernateUtil.TimeSpan.NullSafeSet(cmd, null, index + 1);
            }
            else
            {
                var tuple = (Tuple<int, String>)value;
    
                PropertyTypes[0].NullSafeSet(cmd, tuple.Item1, index, session);
                PropertyTypes[1].NullSafeSet(cmd, tuple.Item2, index + 1, session);
            }
        }
    
        public object DeepCopy(object value)
        {
            var tuple = (Tuple<int, String>)value;
            return Tuple.Create(tuple.Item1, tuple.Item2);
        }
    
        public object Disassemble(object value, ISessionImplementor session)
        {
            return DeepCopy(value);
        }
    
        public object Assemble(object cached, ISessionImplementor session, object owner)
        {
            return DeepCopy(cached);
        }
    
        public object Replace(object original, object target, ISessionImplementor session, object owner)
        {
            return DeepCopy(original);
        }
    
        public string[] PropertyNames { get { return new[] { "Item1", "Item2" }; } }
        public IType[] PropertyTypes { get { return new IType[] { NHibernateUtil.Int32, NHibernateUtil.String }; } }
        public Type ReturnedClass { get { return typeof(Tuple<int, string>); } }
        public bool IsMutable { get { return false; } }
    }
    

    这里有几个例子:
    Money object and NHibernate ICompositeUserType
    Mapping Timestamp data using NHibernate's ICompositeUserType
    Using NHibernate ICompositeUserType with a value type

    您的&lt;composite-element&gt; 映射然后更改为(如NHIbernate: How to map a bag with an ICompositeUserType 中所示):

    <element type="MyNamespace.TupleIntStringType, MyAssembly">
      <column name="DBColumn1" />
      <column name="DBColumn2" />
    </element>
    

    【讨论】:

    • 我没有编辑答案以防我遗漏了什么,但鉴于 ICompositeUserType 的示例实现,映射示例实际上不应该是类型:“MyNamespace.TupleCompositeUserType, MyAssembly”吗?
    • 是的,你是对的。我已更改类名以匹配属性/元素映射中使用的名称。谢谢。
    猜你喜欢
    • 2016-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多