LINQ to SQL IQueryable 是否会被意外评估?
我正在编写一些代码,这些代码采用 LINQ to SQL IQueryable
并添加进一步动态生成的Where 子句。例如,这里是其中一种方法的骨架:
IQueryable<T> ApplyContains(IQueryable<T> source, string field, string value)
{
Expression<Func<T, bool>> lambda;
... dynamically generate lambda for p => p.<field>.Contains(value) ...
return source.Where(lambda);
}
我可以将其中几个方法链接在一起,并以“跳过/获取”页面结束。
我是否正确地认为,当最终评估 IQueryable 时,如果 lambda 表达式中有任何内容无法转换为 SQL,则会引发异常?特别是,我担心我可能会意外地执行一些操作,导致 IQueryable 提前评估,然后继续在内存中评估(从而提取数千条记录)。
从我读过的一些内容来看,我怀疑 IQueryable
不会像这样提前评估。有人可以证实这一点吗?
I am writing some code that takes a LINQ to SQL IQueryable<T>
and adds further dynamically generated Where clauses. For example here is the skeleton of one of the methods:
IQueryable<T> ApplyContains(IQueryable<T> source, string field, string value)
{
Expression<Func<T, bool>> lambda;
... dynamically generate lambda for p => p.<field>.Contains(value) ...
return source.Where(lambda);
}
I might chain several of these methods together and finish off with a Skip/Take page.
Am I correct in thinking that when the IQueryable
is finally evaluated if there is anything in the lambda expressions that can't be translated to SQL an exception will be thrown? In particular I'm concerned I might accidentally do something that would cause the IQueryable
to evaluate early and then continue the evaluation in memory (thereby pulling in thousands of records).
From some things I've read I suspect IQueryable
will not evaluate early like this. Can anyone confirm this please?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
是的,您的想法是正确的,如果部分表达式无法转换为 SQL,您的 IQueryable 可能会在运行时抛出错误。因此,我认为最好将查询放在业务层类(如数据服务或存储库)中,然后确保自动化测试涵盖该查询。
关于 Linq 表达式在意外时间求值,要记住的基本规则是,每当您对其调用 foreach 时,表达式都会求值。这还包括在幕后调用 foreach 的方法,例如
ToList()
和FirstOrDefault()
。顺便说一句,判断一个方法是否要调用 foreach 并强制 lambda 求值的一个简单方法是检查该方法的返回值是否是 IQueryable。如果返回值是另一个 IQueryable,则该方法可能只是添加到表达式中,但不会强制其求值。如果返回值是
List
、匿名类型或任何看起来像数据而不是 IQueryable 的值,则该方法必须强制表达式进行计算才能获取该数据。Yes you are correct in thinking that your IQueryable can throw an error at runtime if part of the expression can't be translated into SQL. Because of this I think it's a good idea to have your queries in a Business Layer class (like a data service or repository) and then make sure that query is covered by an automated test.
Regarding your Linq expression evaluating at an unexpected time, the basic rule to keep in mind is that your expression will evaluate whenever you call a foreach on it. This also includes methods that call a foreach behind the scenes like
ToList()
andFirstOrDefault()
.BTW an easy way to tell if a method is going to call a foreach and force your lambda to evaluate is to check whether the return value on that method is an IQueryable. If the return value is another IQueryable then the method is probably just adding to the expression but not forcing it to evaluate. If the return value is a
List<T>
, an anonymous type, or anything that looks like data instead of an IQueryable then the method had to force your expression to evaluate to get that data.你的想法是正确的。
只要您在Where子句中传递
IQueryable
一个Expression
,它就不会意外地求值。另外,以“To”开头的扩展方法将导致计算(即ToList()、ToArray())。
Your thinking is correct.
As long as you pass the
IQueryable
anExpression
in your Where clauses it will not evaluate unexpectedly.Also, the extension methods beginning with "To" will cause evaluation (i.e. ToList(), ToArray()).