好吧,我看到一些帖子几乎要问同样的事情但是点数有点不同.
这是一个经典案例:我正在保存/更新一个实体,并且在同一个会话中,我试图通过FlushMode = Auto从数据库中获取它们(使用criteria/find/enumerable/etc).问题是:NHibernate在查询之前没有刷新更新,所以我从数据库中获取了不一致的数据.
有些人会说,"足够公平",正如文件所述:
此过程刷新默认情况下发生在以下几点:
- 来自Find()或Enumerable()的一些调用
- 来自NHibernate.ITransaction.Commit()
- 来自ISession.Flush()
大胆的"一些调用"清楚地表明NH根本没有责任.但是,IMO在这里遇到了一致性问题,因为该文档还指出:
除非明确表示Flush(),否则绝对无法保证Session何时执行ADO.NET调用,只保证执行它们的顺序.但是,NHibernate确保ISession.Find(..)方法永远不会返回陈旧数据; 他们也不会返回错误的数据.
因此,如果我使用CreateQuery(查找替换)并过滤属性值为20的实体,NH可能不会返回值为30的实体,对吧?但这就是事实上发生的事情,因为Flush不应该自动发生.
public void FlushModeAutoTest()
{
ISession session = _sessionFactory.OpenSession();
session.FlushMode = FlushMode.Auto;
MappedEntity entity = new MappedEntity() { Name = "Entity", Value = 20 };
session.Save(entity);
entity.Value = 30;
session.SaveOrUpdate(entity);
// RETURNS ONE ENTITY, WHEN SHOULD RETURN ZERO
var list = session.CreateQuery("from MappedEntity where Value = 20").List<MappedEntity>();
session.Flush();
session.Close();
}
Run Code Online (Sandbox Code Playgroud)
毕竟:我错了,它是一个错误还是一个不可预测的功能所以每个人都必须打电话给Flush以确保它的工作?
谢谢.
菲利佩
使用OracleConnection与TransactionScope时出现这种奇怪的行为.如果我尝试在事务范围中使用connection.BeginTransaction(),我会得到简单优雅的InvalidOperationException:Connection已经是本地或分布式事务的一部分.
这是一些代码:
var trxOptions = new TransactionOptions();
trxOptions.IsolationLevel = IsolationLevel.ReadCommitted;
using (var transaction = new TransactionScope(TransactionScopeOption.Required,trxOptions))
{
var c = ConfigurationManager.ConnectionStrings["oracle_test"].ConnectionString;
using (var oracle = new OracleConnection(c))
{
oracle.Open();
using (var tr = oracle.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
{
var cmd = oracle.CreateCommand();
cmd.CommandText = "INSERT INTO simple_user VALUES('a')";
cmd.ExecuteNonQuery();
tr.Commit();
}
}
// now go to sql server and insert data
transaction.Complete();
Run Code Online (Sandbox Code Playgroud)
}
如果我不使用BeginTransaction一切正常.有什么想法让它发挥作用?
PS:我在Sql Server上没有这样的问题.
编辑
谢谢你的答案,我想我应该添加一些编辑,以使我的问题清楚.
首先,我上面提供的代码是问题的证明.让我说我有两个DLL的MyProject.Oracle.dll和MyProject2.MsSql.dll,我想使用这些DLL中的方法,他们使用db.BeginTransaction().如果这些dll使用了TransactionScope,我的外部事务就不会成为问题.分配交易将在没有任何问题的情况下处理.但我不能改变dll中的代码.
为什么db.BeginTransaction()适用于SqlServer而不适用于Oracle?
以下代码片段适用于SQL Server 2008(SP1),但对于Oracle 11g,对session.BeginTransaction()的调用会抛出异常,并显示消息"Connection已经是本地或分布式事务的一部分"(下面显示的堆栈跟踪) .使用'"NHibernate.Driver.OracleDataClientDriver".
有没有其他人遇到这个?
using (var scope = new TransactionScope())
{
using (var session = sessionFactory.OpenSession())
using (var transaction = session.BeginTransaction())
{
// do what you need to do with the session
transaction.Commit();
}
scope.Complete();
}
Run Code Online (Sandbox Code Playgroud)
Exception at: at NHibernate.Transaction.AdoTransaction.Begin(IsolationLevel isolationLevel)
at NHibernate.Transaction.AdoTransaction.Begin()
at NHibernate.AdoNet.ConnectionManager.BeginTransaction()
at NHibernate.Impl.SessionImpl.BeginTransaction()
at MetraTech.BusinessEntity.DataAccess.Persistence.StandardRepository.SaveInstances(List`1& dataObjects) in S:\MetraTech\BusinessEntity\DataAccess\Persistence\StandardRepository.cs:line 3103
Inner error message was: Connection is already part of a local or a distributed transaction
Inner exception at: at Oracle.DataAccess.Client.OracleConnection.BeginTransaction(IsolationLevel isolationLevel)
at Oracle.DataAccess.Client.OracleConnection.BeginDbTransaction(IsolationLevel isolationLevel)
at …