如果NHibernate是以前失败的事务的一部分,它将不会保存我的对象

时间:2012-08-25 22:30:58

标签: nhibernate transactions oracle11g

我正在使用NHibernate和Oracle,我让NHibernate处理我的表主键的下一个序列值。在下面的代码中,我似乎无法让NHibernate在第二次调用transaction.Commit()时保存我的对象。数据库表ReportSource已经有一个记录,其Name列设置为“test2”,并且我在Name列上设置了唯一约束。所以我希望第一个transaction.Commit()失败。但为什么它是第二个transaction.Commit()失败后我用一个当前不在数据库中的名称更新ReportSource对象?

        using (var session = Ioc.Container.Get<ISession>())
        {
            var db = new ReportSource { Name = "test2", ConnectionString = "test", Provider = "test" };
            using (var transaction = session.BeginTransaction())
            {
                try
                {
                    session.SaveOrUpdate(db);
                    transaction.Commit();
                }
                catch (Exception ex)
                {
                    transaction.Rollback();
                }
            }
            using (var transaction = session.BeginTransaction())
            {
                try
                {
                    db.Name = "test4";
                    //fails with or without the below statement
                    //session.SaveOrUpdate(db);
                    transaction.Commit();
                }
                catch (Exception ex)
                {
                    transaction.Rollback();
                }
            }
        }

1 个答案:

答案 0 :(得分:2)

如果在数据库调用期间发生异常,则不应尝试在同一会话中执行任何其他操作。相反,应该丢弃当前会话,因为它不再处于一致状态。这就是NHibernate的文档pointing out

  

如果ISession抛出异常,则应立即回滚   在事务中,调用ISession.Close()并丢弃ISession   实例。某些ISession方法不会将会话留在   一致的状态。

您应该创建另一个会话并重试,而不是尝试在同一会话中拥有另一个事务。

using (var session = Ioc.Container.Get<ISession>())
{
    var db = new ReportSource { 
        Name = "test2", ConnectionString = "test", Provider = "test" };
    using (var transaction = session.BeginTransaction())
    {
        try
        {
            session.SaveOrUpdate(db);
            transaction.Commit();
        }
        catch (Exception ex)
        {
            transaction.Rollback();
        }
    }
}
using (var session = Ioc.Container.Get<ISession>())
{
    using (var transaction = session.BeginTransaction())
    {
        try
        {
            // assign to the new session
            session.Update(db);
            db.Name = "test4";
            session.SaveOrUpdate(db);
            transaction.Commit();
        }
        catch (Exception ex)
        {
            transaction.Rollback();
        }
    }
}