Мне явно не хватает чего-то (надеюсь, очевидно), и до сих пор мне не повезло с Google.
У меня есть отношение родитель-ребенок, отображаемое следующим образом
Упрощенная родительская карта
public sealed class ParentMap : ClassMap<ParentEntity>
{
public ParentMap()
{
Table("Parent");
Component(x => x.Thumbprint);
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.ServeralNotNullableProperties).Not.Nullable();
HasMany(x => x.Children).KeyColumn("ChildId")
.Inverse()
.LazyLoad()
.Cascade
.AllDeleteOrphan();
References(x => x.SomeUnrelatedLookupColumn).Column("LookupColumnId").Not.Nullable();
}
}
Упрощенная карта ребенка
public sealed class ChildMap : ClassMap<ChildEntity>
{
public ChildMap()
{
Table("Child");
Component(x => x.Thumbprint);
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.MoreNotNullableProperties).Not.Nullable();
References(x => x.Parent).Column("ParentId").Not.Nullable();
}
}
Шаги упрощенного сервисного метода
Затем у меня есть метод службы, который извлекает Parent и добавляет нового Child через некоторый метод домена. Основной код NHibernate сводится к следующему:
1) Сессия, открытая в WCF AfterReceiveRequest (IDispatchMessageInspector)
_sessionFactory.OpenSession();
2) Получить существующий экземпляр родителя через .Query
_session.Query<ParentEntity>()
.Where(item => item.Id == parentId)
.Fetch(item => item.SomeLookupColumn)
.First();
3) Добавить новый объект "Child" в "Parent" с помощью метода объекта домена, например...
public ChildEntity CreateChild()
{
var child = new ChildEntity{ Parent = this };
Children.Add(child);
return child;
}
4) В конечном итоге вызовы SaveOrUpdate на объекте Parent.
// ChildEntity Id is 0
_session.SaveOrUpdate(parentEntity)
// Expect ChildEntity Id to NOT be 0
Примечание. Использование SaveOrUpdate Сохраняет изменения в базе данных; использование результатов слияния в TransientObjectException, упомянутых ниже.
5) Наконец, транзакция, выполненная в WCF BeforeSendReply (IDispatchMessageInspector)
_session.Commit();
Проблема
Обычно, когда объект сохраняется, после вызова SaveOrUpdate Идентификатор упомянутого объекта определяет идентификатор, сгенерированный оператором INSERT. Однако, когда я добавляю новый дочерний объект к существующему родительскому объекту, связанный объект в Children
не получает идентификатор. Мне нужно передать этот идентификатор обратно вызывающему, поэтому последующие вызовы приводят к UPDATES, а не дополнительным INSERTS.
Почему NHibernate не обновляет базовый объект? Должен ли я явным образом вызывать SaveOrUpdate для дочернего элемента (что отстойно, если это так)?
Любые мысли по этому поводу получили высокую оценку. Спасибо!
ИЗМЕНИТЬ Следует отметить, что новый дочерний объект IS сохраняется как ожидалось; Я просто не возвращаю идентификатор.
UPDATE Попробовал переключиться на .Merge(~), как предложил Майкл Буэн ниже; в результате чего TransientObjectException говорит мне явно сохранить измененный дочерний объект перед вызовом слияния. Я также экспериментировал с .Persist(~) безрезультатно. Любое дополнительное понимание очень ценится.
объект - несохраненный экземпляр переходного процесса - сохраните временный экземпляр перед слиянием: My.NameSpace.ChildEntity