У меня была точно такая же проблема.Мне пришлось запустить обновление некоторых сообщений, прежде чем я сделаю вставку.Затем, когда я собирался сделать вставку, я получил ошибку, что объект уже используется.
SaveOrUpdate дал мне эту ошибку, и ofc Update тоже.Слияние сработало, НО это сохранило только родительский объект, а не дочерние объекты.
Соединение, однако, заключается в том, что дочерний объект является ответственным за сохранение (в mapobject.
HasMany(x => x.Info)
.Cascade.SaveUpdate();
, так что я думаю, что честно, он вроде работает как задумано.
Раздражает то, что если вы используете SaveOrUpdate для родительского объекта, он на самом деле обновит и дочерние элементы, поскольку он понимает соединение. Но если вы используете Merge, он вообще не будет понимать соединение!
Вот немного этого кода
public AlertEntity InsertCapAlerts(AlertEntity capMessage)
{
using (var transaction = _session.BeginTransaction(IsolationLevel.ReadCommitted))
{
var getCap = GetCapAlert(capMessage.Id);
if (getCap != null)
{
InfoEntity infoToSave = capMessage.Infos.FirstOrDefault();
_session.Merge(infoToSave);
_session.Merge(capMessage);
}
else
_session.Save(capMessage);
transaction.Commit();
return capMessage;
}
}
По сути, я сделал следующее: когда я получаю свое новое capMessage, которое я собираюсь сохранить, я сначала проверяю, существует ли он уже в БД.тогда нет, тогда хорошо, просто сделайте Save (). Но если он существует (вот где SaveOrUpdate всегда падал), тогда я просто создаю новый экземпляр дочерней записи (у нас есть только один дочерний элемент, поэтому FirstOrDefault ()).
Первая попытка, которую я только что сохранил объект Child в БД с помощью Merge (потому что SaveOrUpdate по-прежнему выдает ошибку из-за объекта, использованного в предыдущем сеансе, и да, ябуду пробовать session.Clear () и Flush, а что нет).Это сработало, но потом я заметил, что мой дочерний объект больше не указывает на своего родителя.Таким образом, дочерний объект - теперь сирота, плачущая на улицах базы данных.Поэтому нам нужно снова указать идентификатор родительского объекта на дочерний объект.
InfoEntity infoToSave = capMessage.Infos.FirstOrDefault();
infoToSave.AlertEntity_id = capMessage.Id;
_session.Merge(infoToSave);
_session.Merge(capMessage);
Почему вы спрашиваете?Потому что nHibernate очень симпатичен тем, что когда он запускает Merge, он не говорит о дочерних записях (как это происходит при запуске SaveOrUpdate, как я упоминал ранее).Поэтому, когда вы используете Merge, вы должны обновить все дочерние посты самостоятельно и снова указать на Родителя.
Если кто-то знает лучшее решение для этого.Пожалуйста, сообщите мне.В противном случае, я надеюсь, что этот небольшой пример кода кому-нибудь поможет:)