У нас есть довольно большая БД (~ 200 таблиц), которая почти полностью использует составные первичные ключи и составные внешние ключи, используя единственную «базовую таблицу», от которой каждая другая таблица наследует часть своего первичного ключа:
- Родительский элемент имеет первичный ключ ParentId с одним столбцом
- У ребенка есть составной первичный ключ (ParentId, ChildId) и внешний ключ ParentId
- Племянник имеет составной первичный ключ (ParentId, NephewId), внешний ключ ParentId и внешний ключ (ParentId, ChildId)
и так далее. До сих пор мы управляли всей этой шебангой с помощью нашей собственной структуры 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>
I can post the classes too if you want, I'll omit them now for brevity (as I'll omit the mapping for Parent, since it doesn't have problems). Every property is virtual, every mapping file is an embedded resource, every composite Id has its own class which overrides Equals and 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 прямо сейчас, хотя это может быть вариант, но я предпочел сначала изучить основы;
- Да, мы понимаем, что составные первичные ключи - это большая головная боль. Эта БД за годы прошла через несколько рук, вероятно, не очень опытных, но перед ее рефакторингом мы посчитаем до 10 000