是否可以在对 Where 的调用中调用命名方法?

Posted

技术标签:

【中文标题】是否可以在对 Where 的调用中调用命名方法?【英文标题】:Is it possible to call named method within a call to Where? 【发布时间】:2012-10-15 20:04:19 【问题描述】:

我试图从 RedGate 的这本免费电子书中了解 Linq 的一些性能影响 ftp://support.red-gate.com/ebooks/under-the-hood-of-net-memory-management-part1.pdf

在本书的第 157-158 页,他们创建了以下示例。

Order[] pastDueAccounts = null;  
DateTimedueDate = DateTime.Today.AddDays(-7);  
using(varcontext = new Context())    
  
    pastDueAccounts = context.Accounts.Where(account => account.DueDate < dueDate).ToArray();  
 

然后他们将部分 lamda 表达式重构为以下函数。

public bool PastDueAccount(Account account)  
  
    return account.DueDate < DateTime.Today.AddDays(-7);  
 

最后他们使用这个函数如下。

Order[] pastDueAccounts = null;  
using(varcontext = new Context())  
  
    pastDueAccounts = context.Accounts.Where(account => PastDueAccount(account)).ToArray();  
 

根据我目前的研究,无法运行此 linq 查询,因为 LINQ 无法识别该方法并且无法转换为存储表达式。我想知道这个示例是否错误并且根本无法运行,或者我只是很难了解如何模拟这个问题?

【问题讨论】:

【参考方案1】:

您是对的,LINQ-to-Entities 无法按照它的显示方式调用它。

在 LINQ-to-Entities 中使用它的唯一方法是:

在服务器端创建等效的函数。 适当地Map the function in the model 以便正确翻译调用。

【讨论】:

使用 LINQKit 的 AsExpandable() 是另一种选择,您可以使用能够转换为 SQL 的表达式方法。 @casperOne:关于您对悬停在 VS.NET 中的 Where 上的 Where 调用 t 和 h 的评论,它如何确定何时使用 IEnumerable 调用 Where 以及何时使用 IQueryable 调用 Where?跨度> @palmsnow 基本上类型推断决定了最合适的。在这种特殊情况下,由于参数是Func&lt;T, TResult&gt; 而不是Expression&lt;Func&lt;T, TResult&gt;&gt;,它不能与Queryable.Where(接受表达式)匹配,只能匹配Enumerable.Where(接受委托)。【参考方案2】:

正如 casperOne 所说,你不能用函数来做到这一点。这个答案是一种做你需要做的事情的方法(重复使用 where 过滤器)。

您可以在可以访问的地方创建Expression,然后重复使用它。

System.Linq.Expressions.Expression&lt;Func&lt;Account, bool&gt;&gt; pastDueAccountFunc = account =&gt; account.DueDate &lt; System.Data.Objects.EntityFunctions.AddDays(DateTime.Now, -7);

以后再用:

var pastDueAccounts = context.Accounts.Where(pastDueAccountFunc);

这是我使用的完整代码:

System.Linq.Expressions.Expression<Func<SomeNeatEntity, bool>> func = x => x.DateCreated < System.Data.Objects.EntityFunctions.AddDays(DateTime.Now, -7);

var entities = new MyEntities();

var t = entities.SomeNeatEntities.Where(func);
Console.WriteLine(t.Count());

var h = entities.SomeNeatEntities.Where(x => x.SomeField != null).Where(func);
Console.WriteLine(h.Count());

MyEntities 是项目中的ObjectContextentities.SomeNeatEntitiesObjectSet&lt;SomeNeatEntity&gt;

【讨论】:

这是错误的,并且不会起作用,因为这不是 lambda 表达式,不能由查询提供程序评估。 如果它正常工作,您正在过滤 在客户端,并且对 Where 的调用正在评估来自 IEnumerable&lt;T&gt;not的结果> 将过滤器翻译到服务器端。请记住,IQueryable&lt;T&gt; 派生自IEnumerable&lt;T&gt;,因此IEnumerable&lt;T&gt; 上的所有扩展方法都将适用于IQueryable&lt;T&gt;,而且转换发生的位置并不总是很明显。 我在我的 EF 上下文中直接使用 func。 它是否对我有用,纯粹是因为我将它们都放在同一个代码块中? 对于查询t,来自SomeNeatEntities所有 实体都通过网络传输,然后您在客户端将其过滤掉。在查询h 中,对Where第一次 调用被转换为SQL,其结果通过对Where第二次 调用进行过滤。如果您将鼠标悬停在 VS.NET 中的 Where 方法上,您会看到对于 t 和第二个 Where 调用 h,它正在调用 Enumerable.Where,但在第一次调用 Whereh 上,它调用Queryable.Where,lambda 表达式是Expression&lt;Func&lt;SomeNeatEntity, bool&gt;&gt;;其他人是代表。

以上是关于是否可以在对 Where 的调用中调用命名方法?的主要内容,如果未能解决你的问题,请参考以下文章

如何在对方法 onDestinationChanged() 的调用中获取选定的 Fragment 实例

在对 WebMethod 的 jQuery AJAX 调用中获取空响应,但 Web 方法返回 JSON

从超类调用子类的方法

03. 资源

以编程方式,在对SAP的调用中使用X.509客户端证书需要做什么?

RecursionError:重命名列条目后调用 Python 对象时超出最大递归深度