NHibernate IQueryable 似乎不会延迟执行

Posted

技术标签:

【中文标题】NHibernate IQueryable 似乎不会延迟执行【英文标题】:NHibernate IQueryable doesn't seem to delay execution 【发布时间】:2012-01-20 15:43:39 【问题描述】:

我正在使用 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,而第二个过滤器和选择必须在事后完成。我认为 LINQ 的全部意义在于它形成了一个表达式树,在需要时可以解开它,因此可以为该作业创建正确的 SQL,从而保存我的数据库请求。

如果不是,这意味着我的所有存储库方法都必须准确返回所需的内容,并且我不能在不受到惩罚的情况下进一步利用 LINQ。

我是不是搞错了?

更新

针对下面的评论:我省略了迭代结果的行,这导致运行初始 SQL (WHERE Active = 1) 并且第二个过滤器 (ID

另外,如果我将第二段代码替换为

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

【问题讨论】:

我不确定你的意思,NHibernates IQueryables 肯定会懒惰地评估。当你得到两个数据库查询并期望一个时,你能举个例子吗?这两个示例都只是创建 Queryable 并且不应该生成任何数据库请求。 【参考方案1】:

您正在从该方法返回 IEnumerable&lt;MyModel&gt;,这将导致从该点开始进行内存评估,即使基础序列是 IQueryable&lt;MyModel&gt;

如果您想允许 GetActiveMyModel 之后的代码添加到 SQL 查询中,请改为返回 IQueryable&lt;MyModel&gt;

【讨论】:

@littlecharva:有时只需要第二眼。【参考方案2】:

您正在运行 IEnumerable 的扩展方法“Where”而不是 IQueryable。它仍然会延迟评估并给出相同的输出,但是它会在输入时评估 IQueryable,并且您正在过滤内存中的集合而不是数据库。

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

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

【讨论】:

以上是关于NHibernate IQueryable 似乎不会延迟执行的主要内容,如果未能解决你的问题,请参考以下文章

NHibernate 3 LINQ:如何过滤 IQueryable 以仅选择 T 类及其子类的对象?

NHibernate 似乎没有批量插入 PostgreSQL

Linq to NHibernate 多个 OrderBy 调用

在接口上模拟扩展方法

Fluent NHibernate 主键约束命名约定

NHibernate 通过 Nuget