Ответ 1
Когда использовать inverse = "true | false"
inverse
атрибут используется, чтобы помочь NHibernate узнать, какую сторону отношений следует использовать для сохранения отношений. Не обратная сторона (обратите внимание на двойной отрицательный) - это сторона, которая будет сохраняться. Если ни одна из сторон не является обратной, то связь будет сохраняться дважды, как в случае с INSERT
за которым сразу же следует приведенный выше пример UPDATE
. Если обе стороны обратные, связь не будет сохраняться вообще, поэтому важно правильно установить обратное.
Мне нравится думать об inverse
следующим образом. Я не знаю, официально это работает или нет, но это помогает моему миру понять:
многие-к-одному
many-to-one
всегда inverse="false"
. Они всегда используются для сохранения связи с базой данных. Так как они всегда inverse="false"
, указывать их не нужно, поэтому NHibernate (и, следовательно, Fluent NHibernate) не предоставляет опцию для этого.
(Я сталкивался только одна ситуация, где я хотел бы указать inverse="true"
на many-to-one
. Если у вас есть one-to-many
list
на одной стороне и many-to-one
с другой Кроме того, у вас должна быть возможность позволить list
управлять отношениями, чтобы NHibernate мог позаботиться о настройке значений index
для вас. В его нынешнем виде вы должны добавить свойство в дочерний класс и управлять значениями index
самостоятельно.)
один к одному
one-to-one
всегда inverse="true"
. Они никогда не существуют без id
или " many-to-one
на другой стороне отношений, которые позаботятся о сохранении отношений. Поскольку inverse
значение всегда одинаково, указывать его не нужно, поэтому указание его не поддерживается.
Коллекции
Коллекции, такие как bag
, list
, set
и т.д., Могут быть или не быть частью двунаправленных отношений. Если они существуют сами по себе (возможно, мешок с строковыми элементами), то они должны быть inverse="false"
(по умолчанию), потому что никто не будет нести ответственность за сохранение отношений. Если они существуют в сочетании с другими отношениями, однако (как и ваши традиционные отношения один-ко-многим/многие-к-одному) они должны быть указаны как inverse="true"
.
В случае коллекций " many-to-many
где у вас есть коллекция по обе стороны отношения, пометьте одну из них как inverse="true"
а другую оставьте по умолчанию inverse="false"
. Опять же, дело в том, что одна сторона отношений должна быть не обратной. Какую сторону выбрать? Например, если мы возьмем отношения "многие ко многим" между пользователями и ролями, у вас, вероятно, будет много пользователей и несколько ролей. По моему мнению, вы должны отобразить Role.Users
как inverse="true"
и позволить User.Roles
управлять отношениями, так как это меньший набор данных для работы и, вероятно, коллекция, которая вас больше всего интересует.
(На самом деле, я бы вообще не хотел включать Role.Users
в модель. Предположим, что роль "Клиент" имеет 100 000 пользователей. Тогда customerRole.Users
- непригодная бомба с ленивой загрузкой, ожидающая взрыва.)
... вернуться к вашему вопросу...
Так как на самом деле не имеет значения, какая сторона отношения обратная, если только одна сторона не обратная, то нужно сделать one-to-one
сторону обратной, поскольку именно так NHibernate хочет это сделать. Не боритесь с инструментом за вещи, которые не имеют значения. В предоставленных вами сопоставлениях по существу обе стороны отношения были помечены как не обратные, что привело к тому, что отношение сохранялось дважды. Следующие сопоставления должны работать лучше для вас:
public class Parent
{
public virtual Guid Id { get; set; }
public virtual Child Child { get; set; }
}
public class ParentClassMap : ClassMap<Parent>
{
public ParentClassMap()
{
Id(x => x.Id);
HasOne(x => x.Child)
.PropertyRef(x => x.Parent)
.Cascade.All();
}
}
public class Child
{
public virtual Guid Id { get; set; }
public virtual Parent Parent { get; set; }
}
public class ChildClassMap : ClassMap<Child>
{
public ChildClassMap()
{
Id(x => x.Id);
References(x => x.Parent)
.Not.Nullable()
.Unique()
.Cascade.SaveUpdate();
}
}
... что приводит к следующему SQL из вашего кода вставки теста:
exec sp_executesql N'INSERT INTO [Parent] (Id) VALUES (@p0)',N'@p0 uniqueidentifier',@p0='925237BE-558B-4985-BDA2-9F36000797F5'
exec sp_executesql N'INSERT INTO [Child] (Parent_id, Id) VALUES (@p0, @p1)',N'@p0 uniqueidentifier,@p1 uniqueidentifier',@p0='925237BE-558B-4985-BDA2-9F36000797F5',@p1='BE6D931A-8A05-4662-B5CD-9F36000797FF'
Нет запроса на обновление!