LINQ to SQL:重用lambda表达式 [英] LINQ to SQL: Reuse lambda expression
问题描述
我偶然发现了一些奇怪的LINQ to SQL行为-任何人都可以对此有所了解吗?
I stumbled over some strange LINQ to SQL behaviour - can anybody shed some light on this?
我想定义一个lambda表达式并在我的LINQ语句中使用它.以下代码可以正常工作:
I want to define a lambda expression and use it in my LINQ statement. The following code works fine:
[...]
Func<Table1, bool> lambda = x => x.Id > 1000;
var result = dataContext.Table1s.Where(lambda);
[...]
但是当我尝试在关联表的语句中使用我的lambda表达式时
But when I try to use my lambda expression in a statement on an associated table
[...]
Func<Table1, bool> lambda = x => x.Id > 1000;
var result = dataContext.Table2s.Where(x => x.Table1s.Any(lambda));
[...]
我得到一个例外:
Unsupported overload used for query operator 'Any'.
但是,我没有得到:当我将lambda直接放入查询中时,效果很好:
But, and this I don't get: It works fine when I put my lambda directly into the query:
[...]
var result = dataContext.Table2s.Where(x => x.Table1s.Any(y => y.Id > 1000));
[...]
为什么?!
谢谢.
推荐答案
好的,这是交易:dataContext.Table1s
是IQueryable<T>
类型. IQueryable<T>
定义采用谓词类型为Expression<Func<T, bool>>
的Where
和Any
方法. Expression<>
包装器至关重要,因为这是LINQ to SQL将lambda表达式转换为SQL并在数据库服务器上执行的基础.
Okay, here's the deal: dataContext.Table1s
is of type IQueryable<T>
. IQueryable<T>
defines Where
and Any
methods that take a predicate of type Expression<Func<T, bool>>
. The Expression<>
wrapper is critical, as this is what allows LINQ to SQL to translate your lambda expression to SQL and execute it on the database server.
但是,IQueryable<T>
也包括IEnumerable<T>
. IEnumerable<T>
还定义了Where
和Any
方法,但是IEnumerable版本采用类型为Func<T, bool>
的谓词.由于这是一个编译函数而不是表达式,因此无法将其转换为SQL.结果,此代码...
However, IQueryable<T>
also includes IEnumerable<T>
. IEnumerable<T>
also defines Where
and Any
methods, but the IEnumerable version takes a predicate of type Func<T, bool>
. Because this is a compiled function and not an expression, it can't be translated to SQL. As a result, this code...
Func<Table1, bool> lambda = x => x.Id > 1000;
var result = dataContext.Table1s.Where(lambda);
...将把每个记录从Table1s
中拉出到内存中,然后过滤内存中的记录.可以,但是如果您的桌子很大,那真是个坏消息.
...will pull EVERY record out of Table1s
into memory, and then filter the records in memory. It works, but it's really bad news if your table is large.
Func<Table1, bool> lambda = x => x.Id > 1000;
var result = dataContext.Table2s.Where(x => x.Table1s.Any(lambda));
此版本具有两个lambda表达式.第二个是直接传递到Where
的Expression
,其中包含对Func
的引用.您不能将两者混为一谈,并且收到的错误消息告诉您对Any
的调用期望使用Expression
,但您传递的是Func
.
This version has two lambda expressions. The second one, being passed directly into Where
, is an Expression
that includes a reference to a Func
. You can't mix the two, and the error message you're getting is telling you that the call to Any
is expecting an Expression
but you're passing in a Func
.
var result = dataContext.Table2s.Where(x => x.Table1s.Any(y => y.Id > 1000));
在此版本中,您的内部lambda会自动转换为Expression
,因为这是您希望将代码通过LINQ to SQL转换为SQL的唯一选择.在其他情况下,您会强制将lambda设置为Func
而不是Expression
-在这种情况下,您不是这样,因此可以正常工作.
In this version, your inner lambda is automatically being converted to an Expression
because that's the only choice if you want your code to be transformed into SQL by LINQ to SQL. In the other cases, you're forcing the lambda to be a Func
instead of an Expression
- in this case you're not, so it works.
有什么解决方案?实际上很简单:
What's the solution? It's actually pretty simple:
Expression<Func<Table1, bool>> lambda = x => x.Id > 1000;
这篇关于LINQ to SQL:重用lambda表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!