简体   繁体   English

在 LINQ 查询中使用 Func<>

[英]Using Func<> in LINQ Query

I have a Func<ProductItemVendor, bool> stored in CompareProductItemVendorIds .我有一个Func<ProductItemVendor, bool>存储在CompareProductItemVendorIds I would like to use that expression in a LINQ query.我想在 LINQ 查询中使用该表达式。

It appears the following is legal:看起来以下是合法的:

var results =
    Repository.Query<ProductItemVendor>().Where(CompareProductItemVendorIds);

However, the following is not legal:但是,以下情况是不合法的:

var results = from v in Repository.Query<ProductItemVendor>()
              where CompareProductItemVendorIds(v)
              select v;

This code produces an error:此代码产生错误:

The LINQ expression node type 'Invoke' is not supported in LINQ to Entities. LINQ to Entities 不支持 LINQ 表达式节点类型“Invoke”。

Questions:问题:

  1. Why are these statements so different that my Func<> is legal in one but not the other?为什么这些语句如此不同,以至于我的Func<>在其中一个是合法的,而在另一个中不合法? I thought they both basically did the same thing.我认为他们基本上都做了同样的事情。

  2. How can I make this work?我怎样才能使这项工作? Do I have to explicity create my Func<> as an Expression<Func<>> instead?我是否必须明确创建我的Func<>作为Expression<Func<>>代替?

Please see my related question at Using Expression<Func<>> in a LINQ Query .请参阅我在Using Expression<Func<>> in a LINQ Query 中的相关问题。

There is big difference between Expression<Func<T,bool>> and Func<T,bool> . Expression<Func<T,bool>>Func<T,bool>之间有很大的区别。 First one is an expression tree.第一个是表达式树。 You can think of it as description of code.您可以将其视为代码的描述。 Linq to Entities requires expression trees. Linq to Entities 需要表达式树。 Because it needs to build SQL query.因为它需要构建 SQL 查询。 So it needs description of code to translate same actions into SQL.所以它需要代码描述来将相同的操作转换为 SQL。

Second one, Func<T,bool> is a simple method with specified signature.第二个, Func<T,bool>是一个带有指定签名的简单方法。 Nothing special here.这里没什么特别的。 Why its legal here:为什么它在这里合法:

Repository.Query<ProductItemVendor>().Where(CompareProductItemVendorIds);

It's simple.这很简单。 There are two Where extension methods.有两种Where扩展方法。 One fore IQueryable<T> , which expects expression tree (which will be translated into SQL query).一个前IQueryable<T> ,它期望表达式树(将被转换为 SQL 查询)。 And another is extension for IEnumerable<T> which expects ordinal method for in-memory collection filtering (usual C# code).另一个是IEnumerable<T>扩展,它需要用于内存中集合过滤的序数方法(通常是 C# 代码)。 Thus you don't have expression tree, latter one is chosen.因此你没有表达式树,选择后一个。 No SQL generated here.这里没有生成 SQL。 This is your case.这是你的情况。

Now second query:现在第二个查询:

from v in Repository.Query<ProductItemVendor>()
where CompareProductItemVendorIds(v)
select v

Actually it's not same query.实际上这不是相同的查询。 It's equivalent to它相当于

Repository.Query<ProductItemVendor>().Where(v => CompareProductItemVendorIds(v));

And here you have lambda expression, which can be converted into expression tree.在这里你有 lambda 表达式,它可以转换成表达式树。 And another Where extension is used - one for IQueryable<T> .另一个Where扩展被使用 - 一个用于IQueryable<T> So, Linq to Entities tries to convert this expression tree to SQL.因此,Linq to Entities 尝试将此表达式树转换为 SQL。 But what it should convert?但它应该转换什么? Yes, invocation of some in-memory method.是的,调用一些内存中的方法。 And, of course, Linq to Entities fails to do that.当然,Linq to Entities 没有做到这一点。

In order to make your query work, you should use Expression<Func<T,bool>> .为了使您的查询工作,您应该使用Expression<Func<T,bool>> You can build it manually, or you can use lambda expression.您可以手动构建它,也可以使用 lambda 表达式。

The reason your first version works is Linq is being too smart for it's own good.你的第一个版本有效的原因是 Linq 太聪明了,不利于它自己。 The equivalent of your first version is actually相当于你的第一个版本实际上是

IEnumerable<ProductItemVendor> temp = Repository.Query<ProductItemVendor>().AsEnumerable();
var results = temp.Where(CompareProductItemVendorIds);

So when you perform your query you are returning every row in your database then performing a Where in memory on the local computer.所以,当你执行你查询你在你的数据库返回的每一行,然后执行Where在本地计算机上的内存。

To get the Where clause to be performed on the database you must change the type of CompareProductItemVendorIds to be Expression<Func<ProductItemVendor, bool>> .要在数据库上执行 Where 子句,您必须将CompareProductItemVendorIds的类型更改为Expression<Func<ProductItemVendor, bool>>

There is no way to "convert" from Func<TIn, TOut> to Expression<Func<TIn. Tout>>无法从Func<TIn, TOut> “转换”到Expression<Func<TIn. Tout>> Expression<Func<TIn. Tout>> , you must rewrite your code to initially be a expression, you could then convert to Func<TIn, TOut> by calling CompareProductItemVendorIds.Compile() Expression<Func<TIn. Tout>> ,您必须将代码重写为最初是一个表达式,然后您可以通过调用CompareProductItemVendorIds.Compile()转换为Func<TIn, TOut>

Expression<Func<ProductItemVendor, bool>> CompareProductItemVendorIds = //...
Func<ProductItemVendor, bool> CompareProductItemVendorIdsAsFunc = CompareProductItemVendorIds.Compile();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM