Когда использовать обратное = false для отношений NHibernate / Hibernate OneToMany? - PullRequest
70 голосов
/ 30 июня 2009

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

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

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

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

Это все, кажется, имеет смысл до сих пор. Чего я не понимаю, так это: когда вы НЕ захотите использовать обратное = true для отношения один ко многим?

Ответы [ 3 ]

81 голосов
/ 01 июля 2009

Как говорит Матье, единственный случай, когда вы не захотите устанавливать значение 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>

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

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 значение NULL, потому что акт сохранения sm будет вставлен в таблицу SpyMaster и таблицу Spy, и только после этого он обновит таблицу Spy для установки FK. В этом случае, если мы установим inverse = true, FK никогда не будет обновлен.

29 голосов
/ 04 февраля 2011

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

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

Parent => list of Items
Item => Parent

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

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

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

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

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


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

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

15 голосов
/ 01 июля 2009

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

...