是否可以在对 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<T, TResult>
而不是Expression<Func<T, TResult>>
,它不能与Queryable.Where
(接受表达式)匹配,只能匹配Enumerable.Where
(接受委托)。【参考方案2】:
正如 casperOne 所说,你不能用函数来做到这一点。这个答案是一种做你需要做的事情的方法(重复使用 where 过滤器)。
您可以在可以访问的地方创建Expression
,然后重复使用它。
System.Linq.Expressions.Expression<Func<Account, bool>> pastDueAccountFunc = account => account.DueDate < 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
是项目中的ObjectContext
。entities.SomeNeatEntities
是ObjectSet<SomeNeatEntity>
。
【讨论】:
这是错误的,并且不会起作用,因为这不是 lambda 表达式,不能由查询提供程序评估。 如果它正常工作,您正在过滤 在客户端,并且对Where
的调用正在评估来自 IEnumerable<T>
和 not的结果> 将过滤器翻译到服务器端。请记住,IQueryable<T>
派生自IEnumerable<T>
,因此IEnumerable<T>
上的所有扩展方法都将适用于IQueryable<T>
,而且转换发生的位置并不总是很明显。
我在我的 EF 上下文中直接使用 func。
它是否对我有用,纯粹是因为我将它们都放在同一个代码块中?
对于查询t
,来自SomeNeatEntities
的所有 实体都通过网络传输,然后您在客户端将其过滤掉。在查询h
中,对Where
的第一次 调用被转换为SQL,其结果通过对Where
的第二次 调用进行过滤。如果您将鼠标悬停在 VS.NET 中的 Where
方法上,您会看到对于 t
和第二个 Where
调用 h
,它正在调用 Enumerable.Where
,但在第一次调用 Where
在h
上,它调用Queryable.Where
,lambda 表达式是Expression<Func<SomeNeatEntity, bool>>
;其他人是代表。以上是关于是否可以在对 Where 的调用中调用命名方法?的主要内容,如果未能解决你的问题,请参考以下文章
如何在对方法 onDestinationChanged() 的调用中获取选定的 Fragment 实例
在对 WebMethod 的 jQuery AJAX 调用中获取空响应,但 Web 方法返回 JSON