Отображение связанной таблицы в IDictionary ‹Guid, Tuple‹ String, Int32 ››

Скажем, у меня есть две таблицы, tblTestClass и tblTestClassRelated. В таблице tblTestClass есть Id столбец и прочее. Скажем, в таблице tblTestClassRelated есть столбец TestClassId, столбцы SomeGuid, SomeName и SomeValue.

Это сопоставление загрузит столбцы SomeGuid и SomeValue в связанных tblTestClassRelated строках в свойство IDictionary<Guid, Int32> в TestClass:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Test" namespace="Test">

<class name="TestClass" table="tblTestClass" mutable="true">
    <id name="Id" column="Id">
        <generator class="assigned" />
    </id>

    <!-- Snip... -->

    <map name="MyDictionary" table="tblTestClassRelated" lazy="false" generic="true" inverse="false" cascade="all-delete-orphan">
        <key column="TestClassId" />
        <index column="SomeGuid" type="System.Guid" />
        <element column="SomeValue" type="System.Int32" />
    </map>
</class>
</hibernate-mapping>

Теперь мне нужно сделать то же самое, но я хочу загрузить значения Guid, String и Int32 в IDictionary<Guid, Tuple<String, Int32>>.

Можно ли это нанести на карту? Возможно, я прошу слишком многого; просто пытаюсь избежать создания в значительной степени ненужного тупого класса данных.


person Remi Despres-Smyth    schedule 14.10.2016    source источник


Ответы (1)


Я использовал ответ на этот вопрос в качестве отправной точки. Отображение определяет карту для загрузки в словарь, и я определил класс ICompositeUserType для загрузки кортежа. Класс является универсальным, поэтому я могу повторно использовать его с разными двухэлементными кортежами.

Вот отображение:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Test" namespace="Test">

<class name="TestClass" table="tblTestClass" mutable="true">
    <id name="Id" column="Id">
        <generator class="assigned" />
    </id>

    <!-- Snip... -->

    <map name="MyDictionary" table="tblTestClassRelated" lazy="false" generic="true" inverse="false" cascade="all-delete-orphan">
        <key column="TestClassId" />
        <index column="SomeGuid" type="System.Guid" />

            <element type="MyNamespace.NHibTuple`2[[System.String],[System.Int32]], MyAssembly">
                <column name="tableColumnNameForItem1" />
                <column name="tableColumnNameForItem2" />
            </element>
    </map>
</class>
</hibernate-mapping>

И класс ICompositeUserType:

namespace MyNamespace
{
    public class NHibTuple<T1, T2> : ICompositeUserType
    {
        public bool IsMutable { get { return false; } }
        public string[] PropertyNames { get { return new[] { "Item1", "Item2" }; } }
        public IType[] PropertyTypes { get { return new[] { GetNHibernateType<T1>(), GetNHibernateType<T2>() }; } }
        public Type ReturnedClass { get { return typeof(Tuple<T1, T2>); } }

        public object Assemble(object cached, ISessionImplementor session, object owner)
        {
            return DeepCopy(cached);
        }

        public object DeepCopy(object value)
        {
            var tuple = (Tuple<T1, T2>)value;
            return Tuple.Create(tuple.Item1, tuple.Item2);
        }

        public object Disassemble(object value, ISessionImplementor session)
        {
            return DeepCopy(value);
        }

        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 GetPropertyValue(object component, int property)
        {
            var tuple = (Tuple<T1, T2>)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 object NullSafeGet(IDataReader dr, string[] names, ISessionImplementor session, object owner)
        {
            var item1 = (T1)PropertyTypes[0].NullSafeGet(dr, names[0], session, owner);
            var item2 = (T2)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<T1, T2>)value;

                PropertyTypes[0].NullSafeSet(cmd, tuple.Item1, index, session);
                PropertyTypes[1].NullSafeSet(cmd, tuple.Item2, index + 1, session);
            }
        }

        public object Replace(object original, object target, ISessionImplementor session, object owner)
        {
            return DeepCopy(original);
        }

        static IType GetNHibernateType<TYPE>()
        {
            // No default constructor on String, so...
            if (typeof(TYPE) == typeof(String))
                return NHibernateUtil.String;

            var inst = Activator.CreateInstance<TYPE>();
            return NHibernateUtil.GuessType(inst);
        }
    }
}
person Remi Despres-Smyth    schedule 18.10.2016