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

StackOverflow https://stackoverflow.com/questions/1061179

Вопрос

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

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

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

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

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

Это было полезно?

Решение

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

Другие советы

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

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

Parent => list of Items
Item => Parent

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

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

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

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

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


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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top