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

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

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

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

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

Пока все это имеет смысл. Чего я не понимаю: когда вы НЕ захотите использовать inverse = true в отношении "один ко многим"?


person James Allen    schedule 30.06.2009    source источник


Ответы (3)


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

person Nigel    schedule 01.07.2009
comment
У меня это не сработало. Он никогда не запускает обновление. Он их только вставляет. - person BradLaney; 31.10.2012

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

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

Parent => list of Items
Item => Parent

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

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

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

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

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


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

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

person Stefan Steinegger    schedule 04.02.2011
comment
я обнаружил, что этот ответ более понятен, чем принятый ответ - person r3try; 27.03.2015
comment
Гораздо проще и по существу, чем мой ответ. - person Daniel Schilling; 04.12.2015

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

person MatthieuGD    schedule 30.06.2009