2012-07-04 2 views
2

У меня есть составное отображение с помощью System.Tuple<int,string>, который выглядит следующим образом:Как я могу использовать NHibernate с неизменяемым типом типа System.Tuple?

<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> 

Я стараюсь возиться с BytecodeProvider, IObjectsFactory, ReflectionOptimizer и этажерки, но я не могу получить NHibernate, чтобы загрузить мой Tuple правильно (все, что я делаю , NHibernate настаивает на создании объекта сначала и заполнении значений позже).

Может ли NHibernate быть каким-то образом принудительно загружать и сохранять неизменные типы?

ответ

3

Вы пытались с ICompositeUserType? Это позволит вам определить отображения, как это для вашей Tuple<int, string> собственности:

<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

Ваше картирование <composite-element> затем изменяется (как показано в NHIbernate: How to map a bag with an ICompositeUserType):

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

я не редактировал ответ в случае, если я что-то не хватает, но, учитывая пример реализации ICompositeUserType, должны не примеры картографирования на самом деле быть типа : «MyNamespace.TupleCompositeUserType, MyAssembly»? –

+0

Да, вы правы. Я изменил имя класса в соответствии с именем, используемым при сопоставлении свойств/элементов. Благодарю. –

Смежные вопросы