当使用Rhino Commons UnitOfWork(在ASPO-MVC的UnitOfWorkApplication中)时,我喜欢使用Rhino Repository静态类来保存这样的实体:
Repository<Car>.Save(new Car(Id = 1));
我发现在调用之后我可以使用以下方法立即获取实体:
Car car = Repository<Car>.Get(1);
这很好用。但是,当我在Rhino UnitOfWork上使用NHibernate Linq提供程序时:
var allCars = (from rep in UnitOfWork.CurrentSession.Linq<Car>()
select rep).ToList();
我得到一个空列表。看来我必须先调用UnitOfWork.Current.Flush()然后才能把车开出来。我不明白为什么,鉴于幕后我假设两种检索方法都在查询相同的会话/工作单元。这是否意味着您应该在每次保存到数据库后调用UnitOfWork.Current.Flush()? NHibernate不应该能够解决何时冲洗自己?或者我误解了什么?
答案 0 :(得分:2)
好吧,虽然对Repository的Get调用可以使用会话缓存,但是可以在缓存中“看到”已保存的汽车:
Car car = Repository<Car>.Get(1); // This works because it uses the same session
linq查询不使用会话缓存:
var allCars = (from rep in UnitOfWork.CurrentSession.Linq<Car>()
select rep).ToList(); // Does not work, even if it is in the same code block and even though it uses the same session
所以最佳做法是任何数据库更改(保存,更新,删除,插入)后面都应该跟着:
UnitOfWork.Session.Flush(),
或包裹在:
With.Transaction(delegate{
// code here
})
或使用[Transaction]装饰您的方法并使用ATM。这将确保后续的linq查询将查看最新数据。
答案 1 :(得分:1)
当您调用Repository.Save时,您将通知存储库持有的会话以跟踪该对象并在下次刷新时将更改同步到数据库。在刷新会话之前,不会对数据库进行任何更改。该对象确实成为会话缓存的一部分,因此将由Get(1)返回。
当您运行查询以填充集合时,会话将查询数据库以获取结果,除非它已缓存这些结果。 由于您尚未更新数据库,因此您添加到会话中的Car将不会成为结果集的一部分。(&lt; - 可能不正确)如果我正确阅读文档,应将查询结果和Save()ed实体添加到会话(第一级)缓存中。这并不一定意味着querystatement.List()
在添加数据库结果后查询缓存...我很难完全了解正在发生的事情。
顺便说一句,我相信您可以将会话设置为autoflush,但我必须查看文档。
更新:
我想我可能会看到这里发生了什么。默认会话FlushMode
为Auto
但Rhino的UnitOfWork.Start()
会创建一个FlushMode
设置为Commit
的会话,这意味着会话不会自动刷新,除非您显式调用Flush()
或提交事务。使用FlushMode
Auto
,NHibernate将(有时?)在查询之前刷新会话以防止返回过时数据。如果我是对的,您的数据库事务看起来像:
SELECT * FROM Car
INSERT INTO Car (...) VALUES (...)
当它自动刷新时,我读过的文档/博客看起来有点模棱两可......最常见的答案是FlushMode = Auto
它有时会刷新,但保证Session.Find
永远不会返回陈旧数据。由于NHibernate Linq实际上只是创建一个Criteria查询,它可能不会触发自动刷新(可能现在已经修复了......很难知道)。
所以在我看来,在你的情况下你想要在保存之后刷新,因为你立即想要检索保存的结果。在您只更新实体的较小工作单元中,单个Commit()就可以了。也许UnitOfWork.CurrentSession.FlushMode = FlushMode.Auto;
可以解决这个问题,但是UOW Factory明确地将模式设置为Commit这一事实似乎鼓励你真正考虑你的UOW边界。
答案 2 :(得分:0)
感谢Stuart Childs,我怀疑他是对的,NHibernate Linq提供商可能会遇到这个问题。我不确定它在幕后做了什么,但它可能会使用不同的会话,如果确实如此,那么在Linq查询“看到”它之前我必须刷新存储库是有意义的。是时候浏览一下源代码了,但是我被告知它会让我的脑袋变得难以理解!