【问题标题】:When do i need to flush Rhino Commons UnitOfWork?我什么时候需要刷新 Rhino Commons UnitOfWork?
【发布时间】:2009-03-19 15:14:02
【问题描述】:

当使用 Rhino Commons UnitOfWork(在 ASP-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 不应该能够计算出何时刷新自身吗?还是我误会了什么?

【问题讨论】:

    标签: repository rhino flush unit-of-work


    【解决方案1】:

    好吧,虽然对 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 查询将查看最新数据。

    【讨论】:

      【解决方案2】:

      当您调用 Repository.Save 时,您正在通知存储库持有的会话以跟踪该对象并在下次刷新时将更改同步到数据库。在刷新会话之前,不会对数据库进行任何更改。该对象确实成为会话缓存的一部分,因此将由 Get(1) 返回。

      当您运行查询以填充集合时,会话会查询数据库以获取结果,除非它已经缓存了这些结果。 由于您尚未更新数据库,因此您添加到会话中的 Car 将不会成为结果集的一部分。(querystatement.List() 在添加数据库结果后会查询缓存...我很难弄清楚到底发生了什么。

      顺便说一句,我相信您可以将会话设置为自动刷新,但我必须检查文档。

      更新:

      我想我可能会看到这里发生了什么。默认会话FlushModeAuto,但Rhino 的UnitOfWork.Start() 会创建一个FlushMode 设置为Commit 的会话,这意味着会话不会自动刷新,除非您明确调用Flush() 或提交事务。使用FlushModeAuto,NHibernate 将(有时?)在查询之前刷新会话,以防止返回过时的数据。如果我是对的,您的数据库事务看起来像:

      SELECT * FROM Car
      
      INSERT INTO Car (...) VALUES (...)
      

      从我读过的文档/博客来看,当它自动刷新时似乎有点模棱两可......最常见的答案是它与FlushMode = Auto 一起刷新“有时”,尽管保证Session.Find 永远不会返回过时的数据。由于 NHibernate Linq 实际上只是创建了一个 Criteria 查询,它可能不会触发自动刷新(也许现在已经修复了......这很难知道)。

      所以在我看来,在您的情况下,您希望在保存后刷新,因为您想立即检索保存的结果。在仅更新实体的较小工作单元中,单个 Commit() 就可以了。也许UnitOfWork.CurrentSession.FlushMode = FlushMode.Auto; 可以解决问题,但 UOW 工厂明确将模式设置为提交这一事实似乎鼓励您真正考虑您的 UOW 边界。

      【讨论】:

      • 但是 UnitOfWork.CurrentSession 应该返回存储库使用的相同会话(正如我从 Rhino 源代码中理解的那样),因此 Linq 查询应该能够“看到”会话缓存中的汽车。如果我使用 UnitOfWork.CurrentSession.Get(1),我会得到汽车。
      • 这可能与 UnitOfWork.CurrentSession 默认设置为仅在提交时刷新有关。见编辑。
      • 好地方。我尝试使用 UnitOfWork.CurrentSession.FlushMode 设置刷新模式,但它似乎没有改变。我喜欢您的想法,即 Linq 提供程序出了问题,可能会打开自己的会话?
      【解决方案3】:

      感谢 Stuart Childs,我怀疑他是对的,问题可能出在 NHibernate Linq 提供程序上。我不确定它在幕后做了什么,但它可能使用不同的会话,如果是这样,那么我必须在 Linq 查询“看到”它之前刷新存储库保存是有道理的。是时候查看源代码了,但有人告诉我,如果想理解它,我会感到头晕目眩!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-08-11
        • 1970-01-01
        • 2010-09-21
        • 2018-02-25
        • 1970-01-01
        • 2012-09-16
        • 1970-01-01
        • 2010-10-15
        相关资源
        最近更新 更多