Ответ 1
каждый объект с действительным идентификатором считается постоянным, поэтому он пытается обновить его в процессе слияния, но поскольку он еще не был сохранен, он терпит неудачу. Вызовите session.Flush()
после session.Update()
Текущий подход
В приложении веб-форм ASP.NET(с использованием Spring.NET и NHibernate) у нас есть агрегированный корень (Person), чьи данные фиксируются на нескольких экранах/страницах. Сущность Person существует до входа в этот рабочий процесс, и все изменения, внесенные в графа объектов Person, являются атомарными и поэтому должны быть сброшены только в базу данных после отправки окончательного экрана.
Чтобы достичь этого, мы сначала загружаем Person (лениво) из базы данных с помощью NHibernate 3.2 в первый раз на первую страницу, а затем мы загружаем и сохраняем сериализованный граф объектов Person в переменную сеанса HTTP, когда мы просматриваем процесс,
После извлечения Person из сеанса HTTP он находится в отключенном состоянии из текущего сеанса NHibernate, поэтому мы повторно присоединяемся, вызывая метод Update() в текущем сеансе, например так:
var sessionPerson = Session[PersonSessionName] as Person;
var currentSession = SessionFactory.GetCurrentSession();
currentSession.Update(sessionPerson);
Примечание. Использование Блокировка() создало исключение, сообщив, что "связанный с объектом объект имеет грязную коллекцию".
При повторном подключении мы можем пройти через графический объект, как ожидалось, вытаскивая данные из базы данных для дочерних объектов, которые еще не были загружены в память.
Подмножество файлов сопоставления
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="false" assembly="Domain" namespace=" TestApp.Domain">
<class name="Person" table="Person">
<id name="Id">
<generator class="TestApp.CustomNHibernateHiLoGenerator, TestApp.Core" />
</id>
<property name="Name" not-null="false" />
<bag name="PersonCountries" access="field.camelcase-underscore" cascade="all-delete-orphan">
<key column="PersonId" foreign-key="FK_ PersonCountry_Person" not-null="true" />
<one-to-many class="PersonCountry" />
</bag>
</class>
<class name="Country" table="Country">
<id name="Id">
<generator class="TestApp.CustomNHibernateHiLoGenerator, TestApp.Core" />
</id>
... No back reference to Person
</class>
</hibernate-mapping>
Домен
public class PersonCountry : Entity, ICloneable
{
// No properties of note
}
public class Person : Entity, ICloneable
{
public virtual string Name { get; set; }
public virtual IEnumerable<PersonCountry> PersonCountries { get; set; }
...
// More Properties
}
Сбрасывание изменений в базу данных
.. // Code-behind
PricingService.Save(ProductContext.Pricing, forceMerge: true);
public class PricingService : IPricingService
{
[Transaction] // Spring.NET transaction
public Pricing Save(Pricing pricing, bool forceMerge = false)
{
if(forceMerge)
{
CurrentSession.Merge(entity);
}
else
{
CurrentSession.SaveOrUpdate(entity);
}
}
}
Когда придет время сбросить все изменения в базу данных, при условии, что мы изменим только имя, изменение будет работать, как ожидалось. Однако добавление нового элемента "Страна" для Person приводит к отказу каскадирования Merge() по отношениям "один ко многим" с последующим исключением (как это ни странно, удаление "Прекрасно работает в стране" ).
NHibernate.StaleStateException: Batch update returned unexpected row count from update; actual row count: 0; Expected: 1
Любая помощь будет принята с благодарностью.
каждый объект с действительным идентификатором считается постоянным, поэтому он пытается обновить его в процессе слияния, но поскольку он еще не был сохранен, он терпит неудачу. Вызовите session.Flush()
после session.Update()