NHibernate 没有接受更改
我想知道在什么情况下以下 NHibernate 代码可能会失败:
var session = NHibernateSessionManager.CurrentSession;
var foo = session.Linq<Foo>.ToList()[0];
foo.SomeProperty = "test";
session.SaveOrUpdate(foo);
var reloadedFoos = session.Linq<Foo>
.Where(x => x.SomeProperty == "test");
Assert.That(reloadedFoos.Count > 0);
Assert 语句总是失败。
如果我在SaveOrUpdate之后手动调用session.Flush,那么select查询会成功,但是我认为我们不必手动调用flush?据我了解,NHibernate 应该足够聪明,能够意识到 Foo 已更新,因此第二个选择查询应该成功。
观察生成的 SQL,似乎第二个选择查询的 SQL 在第一个 SaveOrUpdate 的 SQL 之前执行。
事实上,如果我将整个方法包装在一个事务中,那么它就会成功:
using(NHibernateSessionManager.CurrentSession.BeginTransaction()
{
// Same code as above
}
现在 SaveOrUpdate 的 sql 将在 Linq.Where sql 之前执行。这有点奇怪,因为我什至不必在两者之间提交事务。
到底是怎么回事?
I am wondering under what circumstances the following NHibernate code could fail:
var session = NHibernateSessionManager.CurrentSession;
var foo = session.Linq<Foo>.ToList()[0];
foo.SomeProperty = "test";
session.SaveOrUpdate(foo);
var reloadedFoos = session.Linq<Foo>
.Where(x => x.SomeProperty == "test");
Assert.That(reloadedFoos.Count > 0);
The Assert statement always fails.
If I manually call session.Flush after SaveOrUpdate, then the select query succeeds, however I thought that we did not have to manually call flush? It was my understanding that NHibernate should be smart enough to realise that Foo has been updated, so the second select query should succeed.
Watching the SQL that is generated, it appears the second select query's SQL is executed before the first SaveOrUpdate's sql.
In fact, if I wrap the entire method in a transaction, then it succeeds:
using(NHibernateSessionManager.CurrentSession.BeginTransaction()
{
// Same code as above
}
Now the SaveOrUpdate's sql will execute before the Linq.Where sql. This is a little strange, as I do not have to even commit the transaction in between.
What is going on?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
请注意,您需要一个事务才能使 NHibernate 变得“智能”。
它的工作原理如下:
另请注意,您不在需要时调用
Save
、Update
或SaveOrUpdate
保存您对Session
已跟踪回数据库的对象所做的更改。 NHibernate 的工作方式与其他 ORM 不同:如果它正在跟踪一个对象,那么它会确定何时将更改发送到数据库,并且您不需要告诉它这样做。Note that you need a transaction for NHibernate to be "smart."
Here is how it works:
Note also that you do not call
Save
,Update
, orSaveOrUpdate
when you want to save the changes you have made to an object that theSession
is already tracking back down to the database. NHibernate works differently from other ORMs: if it is tracking an object, then it will figure out when to send down the changes to the database and you don't need to tell it to do so.“我想知道在什么情况下以下 NHibernate 代码可能会失败:”我认为您已经为自己的问题提供了至少一个答案:当代码在隐式事务中运行时。请参阅Ayende 的这篇文章,其中提到了隐式事务中的不一致行为。我有许多类似于您的代码的单元测试,除了测试驱动程序提供包装事务,例如,
[GetAll<>() 是 Linq<> 上的薄包装器。] 我有许多定期通过的此类测试。
"I am wondering under what circumstances the following NHibernate code could fail:" I think you have supplied at least one answer to your own question: when the code is run inside an implicit transaction. See this post from Ayende, which mentions inconsistent behavior inside implicit transactions. I have many unit tests that resemble your code except the test driver supplies a wrapping transaction, e.g.,
[GetAll<>() is a thin wrapper over Linq<>.] I have many such tests that pass regularly.
您可能设置了不正确的冲洗模式。您需要将会话上的刷新模式设置为自动,以便在每次查询之前自动刷新会话,否则您需要手动刷新会话以强制保存更改。
You've probably got the incorrect flushmode set. You need to set the flushmode on the session to Auto for it to automatically flush the session before every query otherwise you need to flush the session manually to force the changes to be saved.
您必须关闭会话并在断言之前创建一个 now 会话。
You have to close the session and create an now one before the Assert.
首先:甚至不需要调用 SaveOrUpdate()。
使用 NH 会话时需要记住以下几点:
因此,在您的情况下,因为您已经从会话加载了一个对象,所以调用 session.Update() 不会执行任何操作,因为它已经被跟踪。事实上,您只需执行以下操作即可强制更新数据库:
For a start: your call to SaveOrUpdate() is not even needed.
Here are some things to remember when using an NH session:
So, in your case, because you have loaded an object from the session already, calling session.Update() does nothing since it is already being tracked. You could infact force an update to the database by merely doing the following:
我建议您利用 NHibernate 事务。如果不使用它们,NHibernate 完全有可能无法确定何时发出 SaveOrUpdate 调用。
您会发现,使用事务时,即使是只读语句也能表现得更好。请参阅http://nhprof.com/Learn/Alert?name=DoNotUseImplicitTransactions进一步的细节。
例如:
I recommend you leverage NHibernate transactions. It's entirely possible that, without their use, NHibernate has no way of determining when to issue your SaveOrUpdate call.
You'll find that even read-only statements perform better when using transactions. Please see http://nhprof.com/Learn/Alert?name=DoNotUseImplicitTransactions for further details.
For example: