0

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

该过程基本上是:

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

这是代码(稍微更改了对象名称):

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 在第二次调用查询时不断返回我过时的对象,而没有外部提交的更改。顺便说一句,信息:在这种情况下,过时的值是版本列的值(测试是否可以在保存之前检测到陈旧的对象状态)。但出于多种原因,我需要新的查询结果!

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

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

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

4

2 回答 2

1

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

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

这是设计使然,并且有充分的理由这样做。

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

或者,您可能想阅读Stateless Sessions

于 2012-07-05T22:57:32.687 回答
0

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

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

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

这要么是问题,要么将来会成为问题。NHibernate 正在尽一切努力让您的生活更美好,但您正在尝试尽可能多地阻止 NHibernate 正常工作。

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

于 2012-07-09T12:08:52.913 回答