我正在使用查询缓存和ORDER BY子句看到NHibernate中的错误...
当我运行以下查询时...
SELECT this_.Id as y0_,
this_.Name as y1_
FROM Products this_
WHERE this_.IsActive = 1
ORDER BY this_.IsPremium desc
...如果我打开了查询缓存,NHibernate会成功缓存其结果,并告诉它缓存此查询(使用例如criteria.SetCacheable(true)
)。
不幸的是,正如精彩的NHProf告诉我的那样,NHibernate在运行此查询时也会使用缓存的查询结果:
SELECT this_.Id as y0_,
this_.Name as y1_
FROM Products this_
WHERE this_.IsActive = 1
ORDER BY this_.IsPremium desc,
this_.Name
任何人都可以解释原因或指出我对这个“功能”的一些深入文档吗?或者,更好的是,是否有人对此问题有解决方案?
答案 0 :(得分:0)
NHibernate使用第一级缓存(由身份映射实现)来缓存您查询的每个对象。 NHibernate适用于单个实体,即使您查询对象列表也是如此。
让我解释一些事情:
您查询是否执行此查询并尝试获取ID为1的实体:
session.get<SomeEntity>(1);
NHibernate将检查缓存以查看它是否已包含id 1。如果是这样,将返回缓存的对象,它将不会运行查询。如果没有,则执行查询,选择记录,将其放入缓存并将其返回给您。如果再次执行查询,则会对其进行高速缓存,并在没有新查询的情况下返回对象。
现在,如果您查询这样的列表:
session.QueryOver<SomeEntity>().List();
nhibernate不知道将获取哪个id,因此它将查询所有记录并逐个检查结果,即使您运行查询两次。假设您的数据库中有2条记录(标识1和2)。当缓存仍为空时,您可以使用查询获取它们。两个记录都被提取,放入缓存并返回给您。现在你插入记录3,4和5,当你在它的时候,你也会更新记录1。现在,如果再次运行查询,它将读取所有5条记录,但现在也会缓存记录3,4和5。您将获得一个包含5个对象的列表,其中3,4,5是刚刚读取的对象,但返回的缓存版本为1和2。你不会得到id 1的更新版本。
因此回答你的问题:改变顺序并不重要。您的查询将导致一组记录逐个检查缓存,如果其中一个已经存在,则返回此缓存版本。
解决问题的方法可能是: