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



使用 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");

无论我做什么,包括放置/刷新缓存模式,用于查询或会话:NHibernate在第二次调用查询时都会向我返回过时的对象,而无需外部提交的更改。信息顺便说一句:在这种情况下,过时的值是版本列的值(用于测试是否可以在保存之前检测到过时的对象状态)。但是出于多种原因,我需要新的查询结果!

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

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

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

首先:这与二级缓存(这是SetCacheModeSetCacheable控制)没有任何关系。即使这样做,这些也控制查询的缓存,而不是返回实体的缓存。

当一个对象已经加载到当前会话中时(也被某些人称为"一级缓存",尽管它不是缓存而是身份映射),使用任何方法从数据库再次查询它永远不会覆盖其值。

这是设计使然,它以这种方式运行是有充分理由的。

如果需要使用查询更新多个记录中可能更改的值,则必须事先Evict它们。

或者,您可能想要阅读有关无状态会话的信息。

此代码是否在事务中运行?还是该外部进程在事务中运行?如果这两者之一仍在事务中,您将看不到任何更新。

如果不是这种情况,您也许能够在 NHibernate 创建的日志消息中找到问题。这些信息量很大,总是会告诉你它在做什么。

保持会话打开状态对于仅对脏列执行动态更新是必要的

这要么是问题,要么将来会成为一个问题。NHibernate正在尽其所能让你的生活更美好,但你正在尽可能多地阻止NHibernate正确地完成它的工作。

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

最新更新