Linq Projection在NHibernate 3.2中被错误缓存

本文关键字:错误 缓存 Projection NHibernate Linq | 更新日期: 2023-09-27 18:19:45

给定如下简单投影,当查询相同时,NHibernate将缓存查询计划,而不更新变量的值:

    int argValue = 1;
    var result1 = database.Users.Select(x => new {x.Name, BadArg = argValue}).First();
    argValue = 2;
    var result2 = database.Users.Select(x => new {x.Name, BadArg = argValue}).First();

预期

result1值为Name="Bob"和BadArg=1

result2值为Name="Bob"和BadArg=2

实际

result1值为Name="Bob"和BadArg=1

result2值为Name="Bob"且BadArg=1

显然,如果你没有预料到的话,这可能会导致很多疯狂的行为。我在NHibernate的错误跟踪中看到了一些类似的错误报告,但自去年5月以来就没有任何行动。所以,要么没有人经常使用Linq来NHibernate,要么有一些我不知道的变通方法。

在我深入研究NHibernate源代码之前,有没有办法禁用查询计划缓存以防止这种行为或其他解决方法,或者有人从上面的链接应用了补丁?

注意

这个例子是为了让问题变得简单,事实上,我有一个复杂的投影,我想保留为IQuerable,过早地转换为IEnumerable是行不通的。

更新在Nhibernate 3.2.1 的github master中不工作

Linq Projection在NHibernate 3.2中被错误缓存

如果您想完全避免缓存,请尝试将代码更改为:

int argValue = 1;
var result1 = database.Users.AsEnumerable().Select(x => new {x.Name, BadArg = argValue}).First();
argValue = 2;
var result2 = database.Users.AsEnumerable().Select(x => new {x.Name, BadArg = argValue}).First();

实际情况是,您最终将使用System.LinqSelect方法,而不是使用NHLinq-Select方法——有效地防止了NHibernate缓存投影。当然,缺点是您将在内存中进行投影,因此您最终将从用户表中选择所有字段,而不是只选择您想要的字段。

以下是如何禁用一级缓存:http://darioquintana.com.ar/blogging/2007/10/08/statelesssession-nhibernate-without-first-level-cache/

我不认为你可以禁用二级缓存,但我认为你不必为这个问题。

(本质上,您需要为每个查询创建和销毁会话。)

如果你发现这个问题仍然存在,你就必须按照Rytmis的建议去做。