在有人将其作为this,this和许多其他类似问题的副本进行投票之前,请仔细阅读该问题,因为我认为不是(即使看起来非常相似) )。
我有一个Linq查询,如下所示...
List<int> ids = ctx
.Where(a => a.PartInformationTypeID == pitID && vals.Contains(a.PartDefinitionID))
.Select(a => a.SystemID)
.Distinct()
.ToList();
......,其中pitID
是int
,而vals
是List<int>
这很好,但是由于我有四个这样的查询,只是Where
子句中的lambda有所不同,我认为最好将代码提取到一个通用方法中……
private List<int> DoAdvancedSearch(Func<MyType, bool> p)
{
return ctx
.Where(a => p(a))
.Select(a => a.SystemID)
.Distinct()
.ToList();
}
然后我可以这样称呼...
List<int> ids = DoAdvancedSearch(systemIDs,
a => a.PartInformationTypeID == pitID && vals.Contains(a.PartDefinitionID))
但是,此方法给出了运行时异常“ System.NotSupportedException:'LINQ to Entities不支持LINQ表达式节点类型'Invoke'。'”
在读取了其他问题的例外情况后,我设法通过如下更改方法来解决它...
private List<int> DoAdvancedSearch(Expression<Func<MyType, bool>> p)
{
return ctx
.Where(p)
.Select(a => a.SystemID)
.Distinct()
.ToList();
}
但是,我似乎找不到的一件事是为什么我上面的第一个查询(带有Where
子句中的lambda)不起作用,而第二个查询是提取方法呢?我认为这与实际的lambda无关,因为它不包含EF无法转换为SQL的任何内容(这在第一个版本中确实如此),因此显然与以下事实有关: lambda作为Func
而不是Expression
传递。
我找到的最接近解释的是对this question的回答,但这是基于以下事实:传入的代码无法转换为SQL。正如我所说,我认为这不是问题所在,因为EF设法在第一个代码段中很好地将其翻译了。
任何人都能解释为什么我的示例不适用于Func
吗?
作为次要问题,任何人都可以解释为什么.Where(a => p(a))
在p
上给出了“ 期望的方法名称”的编译器错误,但对于{{1} }?我认为这些是等效的。
谢谢
答案 0 :(得分:3)
一个Expression对象被编译成一个数据结构(一个表达式树)。 EF在运行时将其转换为SQL代码。另一方面,Func由编译器转换为可执行的IL代码。当您要求EF转换包含Where(x => f(x))的查询时,您将得到一个Func f,它是IL代码,并且周围有一个小的表达式树,描述了对由f表示的函数的调用。错误消息的意思是该“调用”表达式树无法转换为SQL,这是合理的,因为要调用的是一段IL代码。
请注意,在第一个示例中,Where调用是内联的,您使用的是表达式,而不是Func。这是因为C#中的lambda表达式可以同时具有两种类型,并且在IQueryable上使用Where扩展方法时,该参数属于Expression类型,因此整个lambda都被编译为表达式树。
答案 1 :(得分:1)
如果您通过varbinary
,则可能有效。 Experssion<Func<MyType, bool>>
是对.net编译方法的引用。 Func
是一个表达式树,具有与该函数相同的调用签名。