Использование части составного первичного ключа в составном внешнем ключе в NHibernate - PullRequest
1 голос
/ 08 октября 2010

У нас есть довольно большая БД (~ 200 таблиц), которая почти полностью использует составные первичные ключи и составные внешние ключи, используя одну «базовую таблицу», от которой каждая другая таблица наследует часть своего первичного ключа:

  • Родитель имеет первичный ключ из одного столбца ParentId
  • Дочерний имеет составной первичный ключ (ParentId, ChildId) и внешний ключ ParentId
  • У племянника есть составной первичный ключ (ParentId, NephewId), внешний ключParentId и внешний ключ (ParentId, ChildId)

и так далее.До сих пор мы управляли всем этим shebang с помощью собственной платформы ORM, но мы рассматриваем возможность использования NHibernate, который мне поручено изучить (я скачал v2.1.2).

Отображения: Ребенок

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Assembly" namespace="Namespace">
<class name="Child" table="Child">
    <composite-id name="IdChild" class="ChildId">
        <key-many-to-one name="Parent" column="ParentId" class="ParentId"></key-many-to-one>
        <key-property name="Id" column="ChildId" type="Int32"></key-property>
    </composite-id>
    <!--simple properties-->
    <set name="Nephews" table="Nephew">
        <key>
            <column name="ParentId"></column>
            <column name="ChildId"></column>
        </key>
        <one-to-many class="Nephew"/>
    </set>
</class>
</hibernate-mapping> 

Племянник

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Assembly" namespace="Namespace">
    <class name="Nephew" table="Nephew">
        <composite-id name="IdNephew" class="NephewId">
            <key-many-to-one name="Parent" column="ParentId" class="Parent"></key-many-to-one>
            <key-property name="Id" column="NephewId" type="Int32"></key-property>
        </composite-id>
        <many-to-one name="Child" class="Child">
            <column name="ParentId"></column>
            <column name="ChildId"></column>
        </many-to-one>
        <!--simple properties-->
    </class>

Я могу также публиковать классы, если вы хотите, я опущу их сейчас для краткости (как я будуопустите отображение для Родителя, так как у него нет проблем).Каждое свойство является виртуальным, каждый файл сопоставления является встроенным ресурсом, каждый составной Id имеет свой собственный класс, который переопределяет Equals и GetHashCode.

Проблема в том, что я не могу сохранить экземпляр Nephew, инициализированный с помощью простого new Nephew() и передан _session.Save(), потому что я получаю System.IndexOutOfRangeException: Invalid index n for this SqlParameterCollection with Count=n..

Единственный столбец, который дублируется в отображении, это ParentId.Удаляя отображение many-to-one в Nephew, отображение set в Child и все связанные свойства, все работает нормально.

Я нашел несколько сообщений, сообщающих об этом исключении, и наиболее подходящее в моемКажется, дело в , в этом , что дает мне внутреннее ощущение, что моя текущая схема недопустима с NHibernate.Пожалуйста, скажите мне, что я не прав: -)

ПРИМЕЧАНИЯ:

  • Я сейчас не использую Fluent, хотя это может быть вариантом, но я предпочел изучить основыfirst;
  • Да, мы понимаем, что составные первичные ключи - большая боль в заднице.Эта БД прошла через несколько раздач в течение многих лет, вероятно, не столь опытных, но перед ее рефакторингом мы будем считать до 10 000

Ответы [ 2 ]

0 голосов
/ 13 октября 2010

Я нашел лучшее решение:

<many-to-one name="Child" class="Child">
    <formula>ParentId</formula>
    <column name="ChildId"></column>
</many-to-one>

Я уже пробовал это, и это выдало мне ошибку, но затем я заметил этот патч , поэтому я скачал 3.0.0 alpha2, и все заработало правильно! Благодаря этому решению я могу отобразить свойство Nephew.Child таким, каким оно должно было быть.

Мне все еще нужен метод Child.Add(Nephew), хотя (но я понял, что это рекомендуется даже в документации)

0 голосов
/ 08 октября 2010

К сожалению, вы не сможете отобразить эти отношения в их текущей форме, как вы сделали вывод.

Однако, есть обходной путь. Вместо отображения Nephew.Child как множества к одному, сопоставьте ChildId как обычное свойство и используйте запрос, когда вам нужно получить Child.

Есть еще один шанс для взлома. Если и только если Nephew.Child не является нулевым и не изменяемым, вы можете сопоставить ключ, ссылающийся на Child, вместо родителя:

<class name="Nephew" table="Nephew">
  <composite-id name="IdNephew" class="NephewId">
    <key-many-to-one name="Child">
      <column="ParentId">
      <column="ChildId">
    </key-many-to-one>
    <key-property name="Id" column="NephewId"/>
  </composite-id>
</class>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...