2012-01-05 81 views
6

给出一个简单的投影像下面,NHibernate的将缓存查询计划,而不是更新变量的值时,查询是相同的:LINQ的投影正在NHibernate的不正确缓存3.2

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值将是名称= “鲍勃” 和BadArg = 1

RESULT2值将名称= “鲍勃” 和BadArg = 2

实际

RESULT1值将是NAME = “鲍勃” 和BadArg = 1

RESULT2值将是NAME = “鲍勃” 和BadArg = 1

显然,这会导致大量的疯狂的行为,如果你不期待它。我在NHibernate的bug跟踪中看到了类似于couple bug reportscouple bug reports,但自去年5月以来没有任何操作。所以要么没有人使用Linq到Nhibernate,要么有一些我不知道的解决方法。

在我深入研究NHibernate源代码之前,有没有办法禁用查询计划缓存来防止此行为或其他解决方法,或者是否有人从上述链接应用了修补程序?

注意

的例子是为了保持简单的问题,在现实中我有我想保持作为一个IQueryable一个复杂的推算,过早地转化为一个IEnumerable将无法正常工作。

更新 是否在github上掌握了NHibernate的3.2.1

+0

我一直在寻找这个好奇心,它看起来像问题不是NHibernate的缓存本身,它是Linq表达式树缓存。问题是,表达式树被简化了,变量引用简化为一个常量表达式,之后缓存键被构造 - 但那时候并没有告诉范围变量ref和常量之间的区别。 : -/ – Rytmis 2012-01-15 19:13:04

+0

我也一直有这个问题,这是一个浪费时间。每隔几个月它就会恢复原状,我已经忘记了它,只是为了再次发现它。在我的情况下,我不是投射到匿名对象,而是为我自己创作的对象赋值。 – 2012-06-01 19:04:36

回答

0

如果你想完全避免缓存不行,请尝试更改您的代码如下:

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(); 

什么情况是,而不是使用NHLinq Select方法,你最终会使用System.Linq Select方法 - 有效地防止NHibernate缓存投影。当然,缺点是你会在内存中进行投影,所以你最终会从你的用户表中选择所有的字段,而不是你想要的。

+0

我知道这样做会起作用,但会有点失败。我的例子对于这个问题很简单,但实际上我想保留它作为IQueryable。 – 2012-01-06 00:02:29

0

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

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

(从本质上讲,你需要创建和销毁每个查询的会话。)

如果发现问题仍然持续,虽然,你必须做什么Rytmis建议。

+0

好的建议! :-) – Rytmis 2012-01-05 23:35:34

+0

仅仅为了执行查询而创建不同的会话似乎有点沉重,并且可能对来自另一个会话的对象产生不良后果。 – 2012-01-06 00:06:03

+0

取决于你的预测 - 如果你的投影只包含标量值,它应该不成问题。但你说得对,它感觉不对。 – Rytmis 2012-01-06 08:10:37