重复查询不会刷新返回对象的属性

时间:2012-07-05 19:25:12

标签: nhibernate session caching

使用NHibernate进行条件查询时,我希望从缓存中获得新结果,而不是旧结果。

这个过程基本上是:

  1. 将持久对象查询到NHibernate应用程序。
  2. 从外部更改数据库条目(另一个程序,在SSMS / MSSQL中手动编辑等)。
  3. 查询持久性对象(具有相同的查询代码),先前加载的对象应从数据库中刷新。
  4. 这是代码(略微更改的对象名称):

    public IOrder GetOrderByOrderId(int orderId)
    {    
    ...
    IList result;
    var query = 
        session.CreateCriteria(typeof(Order))
            .SetFetchMode("Products", FetchMode.Eager)
            .SetFetchMode("Customer", FetchMode.Eager)
            .SetFetchMode("OrderItems", FetchMode.Eager)
            .Add(Restrictions.Eq("OrderId", orderId));
    query.SetCacheMode(CacheMode.Ignore);
    query.SetCacheable(false);
    
    result = query.List();
    ...
    }
    

    我添加了SetCacheMode和SetCacheable来禁用缓存。此外,NHibernate工厂使用配置参数UseQueryCache = false:

    进行设置
    Cfg.SetProperty(NHibernate.Cfg.Environment.UseQueryCache, "false");
    

    无论我做什么,包括Put / Refresh缓存模式,用于查询或会话:NHibernate在第二次调用查询时不断返回过时的对象,而没有外部提交的更改。 Info btw:这种情况下的过时值是Version列的值(用于测试在保存之前是否可以检测到过时的对象状态)。但出于多种原因,我需要新的查询结果!

    NHibernate甚至会生成一个SQL查询,但它永远不会用于返回的值。

    保持会话打开是必要的,只对脏列进行动态更新(也没有无状态会话解决方案!);我不想在代码中随处添加Clear(),Evict()等,特别是因为查询位于较低级别并且不记得先前加载的对象。悲观锁定会破坏性能(多用户环境!)

    有没有办法通过配置强制NHibernate直接向数据库发送查询并获得新的结果,而不是使用不需要的缓存函数?

2 个答案:

答案 0 :(得分:1)

首先:这与第二级缓存没有任何(这是SetCacheModeSetCacheable控制的)。即使它确实如此,那些控制缓存查询,而不是缓存返回的实体。

当一个对象已经被加载到当前会话中时(某些人也称为“第一级缓存”,虽然它不是缓存而是Identity Map),但是使用任何方法从DB再次查询它永远不会覆盖其价值。

这是设计上的,并且有充分的理由让它以这种方式运作。

如果您需要使用查询更新多个记录中可能更改的值, 以前必须Evict

或者,您可能希望阅读Stateless Sessions

答案 1 :(得分:0)

此代码是否在事务中运行?或者是外部进程在事务中运行?如果其中一个仍在交易中,您将看不到任何更新。

如果不是这种情况,您可能能够在NHibernate创建的日志消息中找到问题。这些内容非常丰富,并且总能告诉您它到底在做什么。

  

保持会话打开是必要的,只对脏列进行动态更新

这是问题,或将来会成为问题。 NHibernate正在尽一切努力让你的生活更美好,但是你正在努力尽可能地防止NHibernate正确地完成它的工作。

如果您希望NHibernate仅更新脏列,您可以查看类映射文件中的dynamic-update-attribute