Навигаторы NHibernate сопоставлены с частью составной ключевой проблемы - использование устаревшей базы данных - PullRequest
6 голосов
/ 21 августа 2010

У нас есть устаревшая база данных, которую мы не можем изменить. И мы пытаемся перейти на NHibernate вместо старого слоя DataAccess, который является мусором и слишком медленным.

у него есть такие таблицы:

Таблица GPI имеет столбцы (PU_ID, PAR_ID, Data, Data2)
Таблица BLOCK имеет столбцы (GA_ID, Data, PAR_ID)
В таблице COMPANY есть столбцы (PU_ID, Data)

Я создал эти сопоставления для таблиц выше:

GPI

<class name="GroupPartnerInterest" table="[GPI]">
    <composite-id >
        <key-property name="GroupId" column="PAR_ID" />
        <key-property name="CompanyId" column="PU_ID" />
    </composite-id>
    <property name="data" column="Data"/>
    <property name="data2" column="Data2"/>
    <many-to-one name="Company" fetch="select" cascade="none">
        <column name="PU_ID"/>
    </many-to-one>
    <set name="Blocks" cascade="none" inverse="true" fetch="select">
        <key property-ref="GroupId">
            <column name="PAR_ID"/>
        </key>
        <one-to-many class="Block"/>
    </set>
</class>

BLOCK

<class name="Block" table="[BLOCK]" >
    <id name="BlockId" column="GA_ID" >
        <generator class="assigned"/>
    </id>
    <property name="data" column="Data"/>
    <property name="GroupId" column="PAR_ID"/>
    <set name="GroupPartnerInterests" cascade="all-delete-orphan" fetch="select">
        <key property-ref="GroupId">
            <column name="PAR_ID"/>
        </key>
        <one-to-many class="GroupPartnerInterest"/>
    </set>
</class>

Компания

<class name="Company" table="[COMPANY]">
    <id name="CompanyId" column="PU_ID">
        <generator class="assigned"/>
    </id>
    <property name="data" column="Data"/>
    <set name="GroupPartnerInterests" cascade="none" inverse="true" fetch="select">
        <key>
            <column name="PU_ID"/>
        </key>
        <one-to-many class="GroupPartnerInterest"/>
    </set>
</class>

Занятия очень простые и понятные. Все они реализуют методы Equals и GetHashCode.

Вот список работающих навигаторов:

  • GroupPartnerInterest.Company - прекрасно работает
  • Company.GroupPartnerInterests - отлично работает
  • GroupPartnerInterest.Company - прекрасно работает

И эти два не удаются:

  • Block.GroupPartnerInterests:

У меня есть тестовый модуль:

[TestMethod]
public void TestGroupPartnerInterests()
{
    using ( ISession session = SessionFactory.OpenSession() )
    {
        IList<Block> blocks = session.CreateCriteria( typeof( Block ) )
            .SetMaxResults( 5 ).List<Block>();

        foreach ( var block in blocks )
        {
            TestContext.WriteLine( "Block #{0}", block.BlockId );

            if ( block.GroupPartnerInterests != null )
            {
                foreach ( GroupPartnerInterest gpi in block.GroupPartnerInterests )
                {
                    TestContext.WriteLine( "Company '{0}':", gpi.Company.CompanyId );
                }
            }
        }
    }
}

Если я закомментирую Блокирует отображение навигации в тесте отображения GPI и выдает некоторые данные:

Блок № 1
Компания "ЛАЛА":
Компания 'LALA SA':
Блок № 2
Компания 'BG PO':
Компания "ЛИМПОПО":
Блок № 3
Компания "ХАХА":
Компания «Другие партнеры»:
Блок № 4

Но тест не пройден со следующей ошибкой:

NHibernate.LazyInitializationException: Initializing [Model.EntityClasses.Block # 999] - не удалось лениво инициализировать коллекцию ролей: Model.EntityClasses.Block.GroupPartnerInterests, сеанс или сеанс не был закрыт.

'999' - это существующий PAR_ID - данные согласованы: есть два блока с этим PAR_ID и несколько записей в GPI.

Почему он закрывает сессию в какой-то момент?

  • GroupPartnerInterest.Blocks:

Модульный тест почти такой же, как я упоминал выше, используются только разные свойства. Ошибка ниже:

NHibernate.MappingException: NHibernate.MappingException: свойство не найдено: GroupId для объекта Model.EntityClasses.GroupPartnerInterest.

Если я удалю «property-ref = GroupId» из элемента навигатора Blocks в отображении GPI, я получу следующее исключение:

NHibernate.

Есть ли способ сопоставить блоки с GPI, чтобы работал навигатор GroupPartnerInterest.Blocks?

Спасибо, Alex

1 Ответ

2 голосов
/ 26 августа 2010

Проблема заключается в следующем:

  • Если у вас есть сущность с составным id, все ссылки на него должны поддерживать составной идентификатор, так что должно быть два внешних ключа.
  • Блоки в GroupPartnerInterest - это набор, поэтому внешний ключ находится в Blocks, указывая на GroupPartnerInterest. Для этого потребуются два внешних ключа, которые недоступны.
  • property-ref - заменить первичный ключ некоторым другим свойством. Следовательно, это свойство таблицы с одной стороны отношения, которое равно GroupPartnerInterest, но нет GroupId.
  • Вы могли бы , вероятно, использовать property-ref для GroupPartnerInterest.Blocks (поскольку отсутствуют два внешних ключа, чтобы Block.PAR_ID указывал на GPI.PAR_ID), но я бы дважды подумал об этом.

Я не могу дать вам рабочее решение здесь. Я не использую составные ключи, и это более сложно. Но есть еще несколько мыслей:

  • Я бы попытался избежать составного ключа. Если это невозможно, напишите класс, который представляет составной ключ. Это значительно облегчает обращение с ним.
  • Я бы старался избегать отношений, которые не основаны на первичном ключе. Могут быть причины поступить иначе, NH поддерживает их, я просто думаю, что они вызывают проблемы.

Почему сессия закрыта? Я не знаю, я бы взглянул на трассировку стека. Это исключение действительно выбрасывает изнутри использующий блок? Или это выброшено из TestCleanup метода?

...