如果NHibernate是该会话中失败事务的一部分,它将不允许我在会话中插入模型

时间:2013-02-17 18:58:14

标签: nhibernate transactions nhibernate-caches

为什么我在第一次尝试插入数据时从数据库中收到错误后才插入模型:

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 个答案:

答案 0 :(得分:4)

当数据库触发异常时,必须关闭(处置)NHibernate会话。在异常之后,不保证它是一致的(内部或DB状态)。

请参阅exception handling in the NHibernate reference一章。

答案 1 :(得分:2)

正如Oskar所说,你应该在异常发生后丢弃一个NHibernate会话。但是,插入失败的原因是您已经通过在其上调用SaveOrUpdate来保持报告的持久性(您应该在此使用Save)。当您在同一个实例上再次调用SaveOrUpdate时,NHibernate会抛出异常,因为该对象已经是持久的。如下重写代码可能会允许插入成功(但不建议这样做):

try {
    using (var transaction = session.BeginTransaction()) {
        report.Name = "theName";                   
        transaction.Commit();
    }
}

在更新示例中,调用SaveOrUpdate没有任何效果,因为当NHibernate加载它时对象变得持久。理解NHibernate的instance states以及如何work with persistent objects是基本的,并且被广泛误解。

更好的方法是在将对象保存到数据库之前验证它们。