意外的Linq行为 - ToList()

时间:2013-01-03 15:51:59

标签: c# .net linq linq-to-nhibernate

理论上我有两个类似的查询返回相同的结果:

var requestNotWorking = SessionManagement.Db.Linq<Item>(false).Where(i => 
                        i.Group != null && i.Group.Id == methodParameter)
                       .ToList();

此请求返回0项,即使它应该返回一项。 以下是对后者的重写,但调用了ToList()方法。此请求有效并返回第一个查询中预期的项目!

var requestWorking = SessionManagement.Db.Linq<Item>(false).ToList().Where(i => 
                     i.Group != null && i.Group.Id == methodParameter).ToList();

注意:SessionManagement.Db.Linq<Item>(false)是一个通用的Linq to Nhibernate方法,其布尔属性确定请求是否必须在缓存(true)或数据库(false)中执行。这种方法应该没有错,因为它在解决方案的许多其他部分正常工作。 Item的映射没什么特别之处:没有包包和以下参数: lazy="false" schema="dbo" mutable="false" polymorphism="explicit"

为什么会这样?

修改

生成的requestNoWorking的sql请求以:

结束

(Item.Group_ID is not null) and Item.Group_ID=@p0',N'@p0 int',@p0=11768

生成的requestWorking的sql请求大致为select * from dbo.Items

3 个答案:

答案 0 :(得分:4)

我假设你在那里进行的nhibernate会话返回一个可查询的东西。如果是这样,则第一个查询的评估将延迟到.ToList()调用,并且整个查询将在服务器上运行。我建议你尽可能在sql服务器上运行一个跟踪,或者下载NHProf以查看正在执行的实际查询是什么。

第二个查询在您点击第一个.ToList()后立即进行评估,因此您将整个表从数据库中拉回来,然后使用.net进行过滤。老实说,我不能告诉你为什么他们会以不同的方式进行评估,但我认为有一些映射/配置导致db查询写得有点错误。

答案 1 :(得分:1)

我对c.Group.Id != null的理论非常感兴趣,虽然它与我解决方案中的其他代码段相矛盾,但我发现它是合乎逻辑的。但是,删除它并没有改变任何东西。我发现删除mutable="false"属性解决了这个问题。这看起来有点神奇,但确实有效。

我发布的请求实际上发生在检查更新/删除可能性的方法中。我的结论是,以某种方式使Item immutable导致结果失败。但我不明白为什么requestWorking工作呢!

答案 2 :(得分:0)

我只能看到,在第二个版本中,你的Where由LINQ to Objects而不是LINQ to NHibernate执行。所以第一个版本必须做一些LINQ to NHibernate不能很好地消化的东西。

思考这是LINQ To NHibernate遇到问题的i.Group != null,看到null的使用是特定于CLR的。您可能需要在LINQ to NHibernate中使用另一个构造来测试空字段值。