NHibernate IQueryable似乎没有延迟执行

时间:2012-01-20 15:43:39

标签: linq nhibernate linq-to-nhibernate

我正在使用NHibernate 3.2,我有一个看起来像的存储库方法:

    public IEnumerable<MyModel> GetActiveMyModel()
    {
        return from m in Session.Query<MyModel>()
               where m.Active == true
               select m;
    }

哪个按预期工作。但是,有时当我使用这种方法时,我想进一步过滤它:

    var models = MyRepository.GetActiveMyModel();
    var filtered = from m in models
                   where m.ID < 100
                   select new { m.Name };

哪个产生与第一个相同的SQL,第二个过滤器和select必须在事后完成。我认为LINQ中的重点在于它形成了一个表达树,在需要时它被解开,因此可以创建正确的作业SQL,从而节省了我的数据库请求。

如果没有,这意味着我的所有存储库方法都必须准确地返回所需的内容,并且我不能在链条中使用LINQ而不会受到惩罚。

我弄错了吗?

更新

响应下面的评论:我省略了迭代结果的行,这导致初始SQL运行(WHERE Active = 1),第二个过滤器(ID <100)显然已完成。 NET。

另外,如果我用

替换第二块代码
var models = MyRepository.GetActiveMyModel();
var filtered = from m in models
               where m.Items.Count > 0
               select new { m.Name };

它生成初始SQL来检索活动记录,然后为每条记录运行一个单独的SQL语句,以找出它有多少个项目,而不是像我期望的那样写一些东西:

SELECT Name 
FROM MyModel m 
WHERE Active = 1 
    AND (SELECT COUNT(*) FROM Items WHERE MyModelID = m.ID) > 0

安东尼

2 个答案:

答案 0 :(得分:7)

您将从该方法返回IEnumerable<MyModel>,即使基础序列为IQueryable<MyModel>,也会从该点开始进行内存中评估。

如果要允许GetActiveMyModel之后的代码添加到SQL查询,请返回IQueryable<MyModel>

答案 1 :(得分:1)

你正在运行IEnumerable的扩展方法“Where”而不是IQueryable。它仍然会懒惰地进行评估并提供相同的输出,但是它会在条目上评估IQueryable,并且您在内存中而不是在数据库中过滤集合。

当您稍后在另一个表(计数)上添加额外条件时,它必须从数据库中懒惰地获取每个Items集合,因为它已经在知道该条件之前已经评估了IQueryable。 p>

(是的,我也想成为IEnumerable上广泛的扩展方法,而不是虚拟成员,但是,唉,它们不是)