Когда использовать inverse = false для отношений NHibernate/Hibernate OneToMany?

Я пытаюсь справиться с инверсионным атрибутом Hibernate, и, похоже, это одна из тех вещей, которые концептуально трудны.

Суть в том, что, когда у вас есть родительский объект (например, родительский), у которого есть коллекция дочерних объектов с использованием сопоставления один-ко-многим, установка inverse = true для сопоставления говорит Hibernate, что "другая сторона (ребенок) несет ответственность за обновление самой себя, чтобы поддерживать ссылку на внешний ключ в своей таблице".

Выполнение этого, кажется, имеет 2 преимущества, когда дело доходит до добавления детей в коллекцию в вашем коде, а затем для сохранения родителя (с каскадным набором): вы сохраняете ненужный клик в базе данных (поскольку без инверсного набора Hibernate считает, что он имеет два места для обновления отношений FK) и в соответствии с официальными документами:

Если столбец  ассоциация объявлена NOT NULL, NHibernate может вызвать нарушения ограничений при создании или обновляет связь. Предотвращать эта проблема, вы должны использовать двунаправленная связь с многозначный конец (набор или сумка) обозначен как inverse = "true".

Все это, кажется, имеет смысл до сих пор. То, что я не получаю, это следующее: когда вы НЕ хотите использовать inverse = true для отношений один-ко-многим?

Ответ 1

Как говорит Маттиу, единственный случай, когда вы не хотите устанавливать inverse = true, - это то, где ребенок не имеет права отвечать за само обновление, например, в случае, когда ребенок не знает его родитель.

Давайте попробуем настоящий мир, а не надуманный пример:

<class name="SpyMaster" table="SpyMaster" lazy="true">
  <id name="Id">
    <generator class="identity"/>
  </id>
  <property name="Name"/>
  <set name="Spies" table="Spy" cascade="save-update">
    <key column="SpyMasterId"/>
    <one-to-many class="Spy"/>
  </set>
</class>

<class name="Spy" table="Spy" lazy="true">
  <id name="Id">
    <generator class="identity"/>
  </id>
  <property name="Name"/>
</class>

У Spymasters могут быть шпионы, но шпионы никогда не знают, кто их spymaster, потому что мы не включили отношения "один к одному" в классе шпиона. Также (удобно) шпион может стать мошенником, и поэтому ему не нужно связываться с spymaster. Мы можем создавать объекты следующим образом:

var sm = new SpyMaster
{
    Name = "Head of Operation Treadstone"
};
sm.Spies.Add(new Spy
{
    Name = "Bourne",
    //SpyMaster = sm // Can't do this
});
session.Save(sm);

В таком случае вы должны установить столбец FK равным нулю, поскольку действие сохранения sm будет вставляться в таблицу SpyMaster и таблицу Spy, и только после этого он обновит таблицу Spy, чтобы установить FK. В этом случае, если бы мы установили inverse = true, FK никогда не будет обновляться.

Ответ 2

Несмотря на высокопринятый принятый ответ, у меня есть еще один ответ на этот вопрос.

Рассмотрим диаграмму классов с этими соотношениями:

Parent => list of Items
Item => Parent

Никто никогда не говорил, что отношение Item = > Parent избыточно для отношения Parent = > Items. Элемент может ссылаться на любого Родитель.

Но в вашем приложении вы знаете, что отношения являются избыточными. Вы знаете, что отношения не нужно хранить отдельно в базе данных. Таким образом, вы решили сохранить его в одном внешнем ключе, указывая с элемента на родителя. Эта минимальная информация достаточно, чтобы создать список и ссылку назад.

Все, что вам нужно сделать, чтобы сопоставить это с NH:

  • использовать один и тот же внешний ключ для обоих отношений
  • сообщите NH, что один (список) является избыточным для другого и может быть проигнорирован при хранении объекта. (Это то, что NH фактически делает с inverse="true")

Это мысли, которые имеют отношение к обратному. Ничего больше. Это не выбор, существует только один способ правильного отображения.


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

Неправильное использование: Если вы используете inverse = "true" в списке, который не имеет избыточности в памяти, он просто не сохраняется. Если вы не укажете обратное value = "true", если оно должно быть там, NH может дважды хранить избыточную информацию.

Ответ 3

Если вы хотите иметь однонаправленную связь, то есть дети не могут перейти к родительскому. Если это так, то столбец FK должен быть NULLABLE, потому что дети будут сохранены перед родителем.