我正在使用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();
}
}
}
答案 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();
}
}
}