我偶然发现了一些奇怪的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));
[...]
为什么?!
感谢。
答案 0 :(得分:19)
好的,这是交易:dataContext.Table1s
类型为IQueryable<T>
。 IQueryable<T>
定义采用Where
类型谓词的Any
和Expression<Func<T, bool>>
方法。 Expression<>
包装器很关键,因为这允许LINQ to SQL将lambda表达式转换为SQL并在数据库服务器上执行它。
但是,IQueryable<T>
还包含IEnumerable<T>
。 IEnumerable<T>
还定义了Where
和Any
方法,但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
的对象的类型。