我正在使用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
安东尼
答案 0 :(得分:7)
您将从该方法返回IEnumerable<MyModel>
,即使基础序列为IQueryable<MyModel>
,也会从该点开始进行内存中评估。
如果要允许GetActiveMyModel
之后的代码添加到SQL查询,请返回IQueryable<MyModel>
。
答案 1 :(得分:1)
你正在运行IEnumerable的扩展方法“Where”而不是IQueryable。它仍然会懒惰地进行评估并提供相同的输出,但是它会在条目上评估IQueryable,并且您在内存中而不是在数据库中过滤集合。
当您稍后在另一个表(计数)上添加额外条件时,它必须从数据库中懒惰地获取每个Items集合,因为它已经在知道该条件之前已经评估了IQueryable。 p>
(是的,我也想成为IEnumerable上广泛的扩展方法,而不是虚拟成员,但是,唉,它们不是)