C# ';LINQ表达式节点类型';调用&x27;在LINQ to实体';当lambda作为参数传递,但不直接使用时

C# ';LINQ表达式节点类型';调用&x27;在LINQ to实体';当lambda作为参数传递,但不直接使用时,c#,entity-framework,linq,lambda,C#,Entity Framework,Linq,Lambda,在任何人投票结束这个问题之前,请仔细阅读这个问题,因为我认为它不是(尽管它看起来非常相似) 我有一个Linq查询,如下所示 List<int> ids = ctx .Where(a => a.PartInformationTypeID == pitID && vals.Contains(a.PartDefinitionID)) .Select(a => a.SystemID) .Distinct() .ToList(); List<

在任何人投票结束这个问题之前,请仔细阅读这个问题,因为我认为它不是(尽管它看起来非常相似)

我有一个Linq查询,如下所示

List<int> ids = ctx
  .Where(a => a.PartInformationTypeID == pitID && vals.Contains(a.PartDefinitionID))
  .Select(a => a.SystemID)
  .Distinct()
  .ToList();
List<int> ids = DoAdvancedSearch(systemIDs,
                 a => a.PartInformationTypeID == pitID && vals.Contains(a.PartDefinitionID))
private List<int> DoAdvancedSearch(Expression<Func<MyType, bool>> p)
{
  return ctx
    .Where(p)
    .Select(a => a.SystemID)
    .Distinct()
    .ToList();
}
我可以这样称呼它

List<int> ids = ctx
  .Where(a => a.PartInformationTypeID == pitID && vals.Contains(a.PartDefinitionID))
  .Select(a => a.SystemID)
  .Distinct()
  .ToList();
List<int> ids = DoAdvancedSearch(systemIDs,
                 a => a.PartInformationTypeID == pitID && vals.Contains(a.PartDefinitionID))
private List<int> DoAdvancedSearch(Expression<Func<MyType, bool>> p)
{
  return ctx
    .Where(p)
    .Select(a => a.SystemID)
    .Distinct()
    .ToList();
}
List id=DoAdvancedSearch(systemid,
a=>a.PartInformationTypeID==pitID&&vals.Contains(a.PartDefinitionID))
但是,此方法会出现运行时异常“System.NotSupportedException:'LINQ to Entities中不支持LINQ表达式节点类型'Invoke'。”

在阅读了大量的其他问题后,我成功地解决了这个问题,方法如下

List<int> ids = ctx
  .Where(a => a.PartInformationTypeID == pitID && vals.Contains(a.PartDefinitionID))
  .Select(a => a.SystemID)
  .Distinct()
  .ToList();
List<int> ids = DoAdvancedSearch(systemIDs,
                 a => a.PartInformationTypeID == pitID && vals.Contains(a.PartDefinitionID))
private List<int> DoAdvancedSearch(Expression<Func<MyType, bool>> p)
{
  return ctx
    .Where(p)
    .Select(a => a.SystemID)
    .Distinct()
    .ToList();
}
私有列表DoAdvancedSearch(表达式p)
{
返回ctx
.其中(p)
.Select(a=>a.SystemID)
.Distinct()
.ToList();
}
然而,我似乎找不到的一件事是为什么上面我的第一个查询(在
Where
子句中使用lambda)不起作用,而提取方法中的第二个查询起作用了?我不认为这是实际lambda的问题,因为它不包含EF无法转换为SQL的任何内容(第一个版本就是如此),所以这显然与lambda作为
Func
而不是
表达式传递有关

我发现最接近解释的是对的回答,但这是基于这样一个事实,即传入的代码无法转换为SQL。正如我所说,我不认为这是这里的问题,因为EF在第一个代码段中成功地将其翻译成了良好的代码

有人能解释为什么我的例子不能使用
函数吗

作为第二个问题,任何能够解释为什么
.Where(a=>p(a))
的人都在
p
上给出了一个编译器错误“应该有方法名”,但对
没有问题。Where(p)
?我认为这些是等价的


感谢

表达式对象被编译成数据结构(表达式树)。EF在运行时将其转换为SQL代码。另一方面,Func由编译器转换为可执行的IL代码。当您要求EF翻译一个包含Where(x=>f(x))的查询时,您有一个Func f,它是IL代码,并且在它周围有一个小的表达式树,描述对由f表示的函数的调用。错误消息的意思是,这个“调用”表达式树无法转换为SQL,这是合理的,因为调用的是一段IL代码


请注意,在第一个示例中,where调用是内联的,您使用的是表达式,而不是Func。这是因为C#中的lambda表达式可以同时具有这两种类型,并且在IQueryable上使用Where扩展方法时,参数是表达式类型,因此整个lambda被编译到表达式树中。

如果传递
表达式,它可能会起作用
Func
是对.net编译方法的引用<代码>ExpressionSee@haim770谢谢,这是一个很好的解释。真遗憾,我没想到去寻找差异!谢谢,这解释得很清楚。在他对我的问题的评论中,有了@haim770这个问题的额外背景,我现在明白了。我才意识到我的第二个问题没有得到答案。你知道为什么
.Where(a=>p(a))
p
上给出了一个编译器错误“应该有方法名”,但是
没有问题。Where(p)
?我认为这些是等价的。再次谢谢你,但我不知道