LINQ to SQL:重用lambda表达式

Han*_*fer 9 linq-to-sql

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

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

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

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

[...]
Func<Table1, bool> lambda = x => x.Id > 1000;
var result = dataContext.Table2s.Where(x => x.Table1s.Any(lambda));
[...]
Run Code Online (Sandbox Code Playgroud)

我得到一个例外:

Unsupported overload used for query operator 'Any'.
Run Code Online (Sandbox Code Playgroud)

但是,我没有得到:当我将lambda直接放入查询时,它工作正常:

[...]
var result = dataContext.Table2s.Where(x => x.Table1s.Any(y => y.Id > 1000));
[...]
Run Code Online (Sandbox Code Playgroud)

为什么?!

谢谢.

Joe*_*ler 19

好的,这是交易:dataContext.Table1s属于类型IQueryable<T>.IQueryable<T>定义WhereAny采用类型谓词的方法Expression<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);
Run Code Online (Sandbox Code Playgroud)

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

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

这个版本有两个lambda表达式.第二个,被直接通入Where,是一种Expression包括一个参考Func.你不能把这两者混在一起,你得到的错误信息就是告诉你,这个号码Any是预期的,Expression但是你正在传递Func.

var result = dataContext.Table2s.Where(x => x.Table1s.Any(y => y.Id > 1000));
Run Code Online (Sandbox Code Playgroud)

在此版本中,您的内部lambda会自动转换为a,Expression因为如果您希望通过LINQ to SQL将代码转换为SQL,那么这是唯一的选择.在其他情况下,你强迫lambda Func而不是Expression- 在这种情况下你不是,所以它的工作原理.

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

Expression<Func<Table1, bool>> lambda = x => x.Id > 1000;
Run Code Online (Sandbox Code Playgroud)