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.

Другие вопросы по тегам