NHibernate не позволит мне вставить модель в сеанс, если она была частью неудачной транзакции в этом сеансе
Почему я не могу просто вставить модель после того, как получаю ошибку из базы данных при попытке вставить ее в первый раз:
Report report = null;
using (var session = SessionFactory.OpenSession()) {
try {
using (var transaction = session.BeginTransaction()) {
report = new Report();
session.SaveOrUpdate(report);//Exception: Name field required
transaction.Commit();
}
}
catch { }
try {
using (var transaction = session.BeginTransaction()) {
report.Name = "theName";
session.SaveOrUpdate(report);
//Causes Exception:
//Row was updated or deleted by another transaction (or unsaved-value
//mapping was incorrect): [ReportViewer.DataAccess.Models.Report#22]
transaction.Commit();
}
}
catch { }
}
Но когда я обновляю существующую модель и получаю сообщение об ошибке, я могу внести свои исправления (в этом случае установить имя) и просто попытаться обновить снова:
Report report = null;
using (var session = SessionFactory.OpenSession()) {
using (var transaction = session.BeginTransaction()) {
report = new Report();
report.Name = "theName";
session.SaveOrUpdate(report);
transaction.Commit();
}
}
using (var session = SessionFactory.OpenSession()) {
//get entity saved from previous session
report = session.Get<Report>(report.Id);
try {
using (var transaction = session.BeginTransaction()) {
report.Name = null;
session.SaveOrUpdate(report);//Exception: Name field required
transaction.Commit();
}
}
catch { }
try {
using (var transaction = session.BeginTransaction()) {
//updates and does not give an error
report.Name = "theName";
session.SaveOrUpdate(report);
transaction.Commit();
}
}
catch { }
}
2 ответа
Как сказал Оскар, вам следует отказаться от сеанса NHibernate после возникновения исключения. Однако причина, по которой вставка завершается неудачно, заключается в том, что отчет уже сделан постоянным путем вызова SaveOrUpdate
на нем (вы должны использовать Save
Вот). Когда вы звоните SaveOrUpdate
снова в том же экземпляре NHibernate выдает исключение, потому что объект уже является постоянным. Переписывание кода следующим образом, вероятно, позволит выполнить вставку успешно (но это не рекомендуется):
try {
using (var transaction = session.BeginTransaction()) {
report.Name = "theName";
transaction.Commit();
}
}
В примере обновления вызов SaveOrUpdate
не имеет никакого эффекта, потому что объект стал постоянным, когда NHibernate загрузил его. Понимание состояний экземпляров NHibernate и того, как работать с постоянными объектами, является фундаментальным и широко неправильно понимаемым.
Гораздо лучший подход заключается в проверке ваших объектов перед сохранением их в базе данных.
Когда возникает исключение, вызванное базой данных, сеанс NHibernate должен быть закрыт (удален). Не гарантируется согласованность (внутренне или с состоянием БД) после исключения.
См. Главу по обработке исключений в справочнике NHibernate.