LINQ to SQL:重用lambda表达式

时间:2010-12-30 11:18:18

标签: linq-to-sql

我偶然发现了一些奇怪的LINQ to SQL行为 - 有人可以对此有所了解吗?

我想定义一个lambda表达式并在我的LINQ语句中使用它。以下代码工作正常:

[...]
Func<Table1, bool> lambda = x => x.Id > 1000;
var result = dataContext.Table1s.Where(lambda);
[...]

但是当我尝试在关联表上的语句中使用我的lambda表达式时

[...]
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直接放入查询时,它工作正常:

[...]
var result = dataContext.Table2s.Where(x => x.Table1s.Any(y => y.Id > 1000));
[...]

为什么?!

感谢。

2 个答案:

答案 0 :(得分:19)

好的,这是交易:dataContext.Table1s类型为IQueryable<T>IQueryable<T>定义采用Where类型谓词的AnyExpression<Func<T, bool>>方法。 Expression<>包装器很关键,因为这允许LINQ to SQL将lambda表达式转换为SQL并在数据库服务器上执行它。

但是,IQueryable<T>还包含IEnumerable<T>IEnumerable<T>还定义了WhereAny方法,但IEnumerable版本采用类型为Func<T, bool>的谓词。因为这是一个已编译的函数而不是表达式,所以它无法转换为SQL。结果,这段代码......

Func<Table1, bool> lambda = x => x.Id > 1000;
var result = dataContext.Table1s.Where(lambda);

...会将Table1s中的每条记录拉入内存,然后过滤内存中的记录。它有效,但如果你的桌子很大,这真的是个坏消息。

Func<Table1, bool> lambda = x => x.Id > 1000;
var result = dataContext.Table2s.Where(x => x.Table1s.Any(lambda));

此版本有两个lambda表达式。第二个是直接传递到Where的{​​{1}},其中包含对Expression的引用。你不能把这两者混在一起,而你收到的错误信息告诉你,Func的电话预计会Any,但你传递的是Expression。< / p>

Func

在此版本中,您的内部lambda会自动转换为var result = dataContext.Table2s.Where(x => x.Table1s.Any(y => y.Id > 1000)); ,因为如果您希望通过LINQ to SQL将代码转换为SQL,那么这是唯一的选择。在其他情况下,你强迫lambda为Expression而不是Func - 在这种情况下你不是,所以它有效。

解决方案是什么?这实际上非常简单:

Expression

答案 1 :(得分:0)

Table1是否引用相同的命名空间?在第一个示例中,您要查询直接位于Table1下的dataContext个对象,在第二个示例中,您要查询Table1对象,这些对象是{{1}的属性。 1}}对象,在最后一个例子中,您正在使用一个解决问题的匿名函数。

我会查找Table2对象的类型,该对象是Table1对象的属性,并将其与直接连接到Table2的{​​{1}}对象进行比较}。我的猜测是它们不同,你的lambda表达式使用的是连接到Table1的对象的类型。