2

我正在使用查询缓存和 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 会成功缓存它的结果,并且我告诉它缓存这个查询(使用 eg 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

任何人都可以解释为什么或向我指出有关此“功能”的一些深入文档吗?或者,更好的是,有没有人能解决这个问题?

4

1 回答 1

0

NHibernate 使用第一级缓存(由身份映射实现)来缓存您查询的每个对象。NHibernate 适用于单个实体,即使您查询对象列表也是如此。

让我解释一些东西:
您查询是否执行此查询并尝试获取 id 为 1 的实体:

session.get<SomeEntity>(1);

NHibernate 将检查缓存以查看它是否已经包含 id 1。如果是这样,缓存的对象将被返回并且它不会运行查询。如果没有,则执行查询,选择记录,将其放入缓存并将其返回给您。如果您再次执行查询,它会被缓存并且对象将在没有新查询的情况下返回。

现在,如果您查询这样的列表:

session.QueryOver<SomeEntity>().List();

nhibernate 不知道将获取哪个 id,因此即使您运行两次查询,它也会查询所有记录并逐一检查缓存结果。假设您的数据库中有 2 条记录(id 1 和 2)。当您的缓存仍然为空时,您可以通过查询获取它们。两条记录都被提取,放入缓存并返回给您。现在您插入记录 3、4 和 5,当您插入时,您也将更新记录 1。现在,如果再次运行查询,它将读取所有 5 条记录,但现在也缓存记录 3、4 和 5。您将获得一个包含 5 个对象的列表,其中 3、4、5 是刚刚读取的对象,但会返回 1 和 2 的缓存版本。你不会得到 id 1 的更新版本。

因此回答您的问题:更改顺序无关紧要。您的查询将生成一组记录,这些记录将逐一检查缓存,如果其中一个已经存在,则返回此缓存版本。

您的问题的解决方案可能是:

  • 使用 session.Refresh(obj); 如果您知道哪些已更新。
  • 从会话中驱逐部分或所有实体(这意味着它们将被抛出缓存并可以通过查询重新获取)。注意:如果您驱逐它们,更改将不会被保存。
  • 您可以使用无状态会话,正如无状态名称所暗示的那样,它没有缓存。
于 2013-06-12T07:41:22.547 回答