C# 为什么LINQ不喜欢内联日期计算?

C# 为什么LINQ不喜欢内联日期计算?,c#,linq,C#,Linq,此LINQ表达式涉及日期时间计算,可编译为: var jobsSinceLastRun = _rep.GetJobs(j => j.CompletedDate > DateTime.Now.AddMonths(-1)); 但当您尝试运行它时,会抛出一个错误: LINQ to Entities无法识别方法“System.DateTime AddMonths(Int32)”方法,并且无法将此方法转换为存储表达式 很容易修复: DateTime oneMonthAgo = DateTim

此LINQ表达式涉及日期时间计算,可编译为:

var jobsSinceLastRun = _rep.GetJobs(j => j.CompletedDate > DateTime.Now.AddMonths(-1));
但当您尝试运行它时,会抛出一个错误:

LINQ to Entities无法识别方法“System.DateTime AddMonths(Int32)”方法,并且无法将此方法转换为存储表达式

很容易修复:

DateTime oneMonthAgo = DateTime.Now.AddMonths(-1);
var jobsSinceLastRun = _rep.GetJobs(j => j.CompletedDate > oneMonthAgo);

但这一点让我想知道,在幕后,是什么导致LINQ拒绝内联计算?抽象的哪个部分失败了?

因为有一个从lambda创建的表达式树,包括这个内联计算。
IQueryable
接口的LINQ方法需要表达式树类型而不是委托。因此,为了表达:

j => j.CompletedDate > DateTime.Now.AddMonths(-1)
EF 6的表达式访问者试图将
DateTime.Now.AddMonths(-1)
转换为SQL,但由于不支持此方法的转换,因此无法将其转换为SQL。例如,在EF Core中,它是受支持的,因此表达式可以被翻译。表达方式:

j => j.CompletedDate > oneMonthAgo

expression visitor可以将
oneMonthAgo
转换为SQL,因为它是一个变量,其值可以包含在SQL中。

如果您使用
实体框架6.x
及更高版本-您可以使用
DateTime
计算LINQ to Entities查询:

var jobsSinceLastRun = _rep.GetJobs(j => j.CompletedDate > DbFunctions.AddMonths(DateTime.Now, -1));

抱怨的是“LINQtoEntities”没有代码在SQL中正确编写该表达式,而不是“LINQ”。当您更改到第二段代码时,LINQ to Entities会看到一个最终值,而不是表达式,SQL可以使用参数轻松处理该值。此外,
j=>j.CompletedDate>DateTime。Now.AddMonths(-1)
将在每次计算表达式时创建一个新实例,这可能不是你想要的只是一个想法。。。但是有了这样的逻辑,使用
DateTime oneMonthAgo=DateTime.Today.AddMonths(-1)可以更好地实现您的意图,否则可能会错过当天早些时候的内容。@IvanStoev问题是“是什么导致LINQ拒绝内联计算”而不是“为什么不支持AddMonths”,因此答案解释说创建了包含此内联计算的表达式树(因此之前不会像OP所想的那样对其求值)。我想这就是这个问题,我在一个愚蠢的问题中找不到这样的解释。@arekzyla够公平的。我将使用
实体框架
标记回滚我的编辑(将问题/答案带回更一般的范围)并收回闭包。这假设OP专门使用实体框架6.x。我不知道你从哪里弄来的assumption@CamiloTerevinto谢谢你的提醒,我已经更新了我的答案。我的回答不仅是为了满足OP的需求,也是为了其他任何人,他们会觉得这很有帮助。