Linq到EntityFramework DateTime


108

在我的应用程序中,我正在使用实体框架。

我的桌子

-Article
-period
-startDate

我需要匹配的记录=> DateTime.Now > startDate and (startDate + period) > DateTime.Now

我尝试了这段代码,但现在可以正常工作了

Context.Article
    .Where(p => p.StartDate < DateTime.Now)
    .Where(p => p.StartDate.AddDays(p.Period) > DateTime.Now)

当我运行代码时,发生以下异常

LINQ to Entities无法识别方法'System.DateTime AddDays(Double)',并且该方法无法转换为商店表达式。


什么类型的periodAddDays如果是,则函数是错误的double
Craig Stuntz 2010年

Answers:


201

使用LINQ to Entity Framework时,Where子句中的谓词将转换为SQL。之所以会出现此错误,是因为没有DateTime.Add()有意义的SQL转换。

一种快速的解决方法是将第一个Where语句的结果读入内存,然后使用LINQ to Objects完成过滤:

Context.Article.Where(p => p.StartDate < DateTime.Now)
               .ToList()
               .Where(p => p.StartDate.AddDays(p.Period) > DateTime.Now);

如果您使用的是.NET 4.0,也可以尝试EntityFunctions.AddDays方法:

Context.Article.Where(p => p.StartDate < DateTime.Now)
               .Where(p => EntityFunctions.AddDays(p.StartDate, p.Period)
                   > DateTime.Now);

注意:EF 6现在System.Data.Entity.DbFunctions.AddDays


42
这是一个危险的解决方法,如果ToList()返回大量数据会怎样?
Stefan P. 2010年

7
感谢EntityFunctions.AddDays提示我正在使用EF .net 4.0,但我不了解EntityFunctions,我们会对其进行研究。
Stefan P.

2
@SaeedAlg-在第一个示例中,有必要将项目读入内存。在第二个示例中,我保留了两个Where子句以匹配原始格式。即使将二者压缩到单个Where子句中,Entity Framework也会生成身份SQL,因此这实际上是可读性问题。
Justin Niessner

2
@Justin Niessner非常感谢,我正在努力做四个小时,您在几秒钟内挽救了我的生命再次感谢
Yucel 2010年

2
当使用EF提供“快速”解决方法时,我们都应避免使用ToList和ToArray方法。以前计算日期并与该值进行比较就一样快,并且可以在EF查询中工作而无需在内存中实例化其结果。
艾萨克·洛洛皮斯

92

我认为这是最后一个答案试图建议的内容,但是与其尝试在p.startdat中添加几天(无法转换为sql语句的内容),而是为什么不做可以等同于sql的操作:

var baselineDate = DateTime.Now.AddHours(-24);

something.Where(p => p.startdate >= baselineDate)

2
@Adrian Carr-对于这种用例可能会更好,但不如EntityFunctions解决方案那么多。在此,第二个操作数不从查询中的另一个实体中检索,而是可以在查询之前进行计算。如果要在db中找到两个操作数,则该EntityFunctions解决方案仍然适用,而此响应的解决方案将不再起作用。
2014年

这是比标记为答案的解决方案更好的解决方案。贾斯汀/已标记答案的响应将从数据库返回不必要的结果。该解决方案实际上是在SQL过滤器中发送日期,并使用SQL过滤出数据,从而提高了性能。
保罗

3

如何从DateTime.Now中减去2天:

Context.Article
.Where(p => p.StartDate < DateTime.Now)
.Where(p => p.StartDate > DateTime.Now.Subtract(new TimeSpan(2, 0, 0, 0)))

老实说,我不确定您要达到的目标,但这可能有用


文章将开始在StartDate上显示,并在x(句点)天后结束。这就是我想要做的。贾斯汀·涅斯纳(Justin Niessner)的第二个解决方案非常适合我想要看到的内容
Yucel,2010年

3

如果您需要将表达式转换为SQL,可以尝试使用

System.Data.Entity.Core.Objects.AddDays方法。

实际上已标记为过时,但它可以工作。应该将其替换为System.Data.Entity.DbFunctions.AddDays,但我找不到它...


这只不过是4年前接受的答案而已!
安德鲁·哈里斯

@AndrewHarris我的答案也是4年前的答案。在答案的第一个版本中,Where(请参阅答案的第一个注释)之前有一个ToList(=>数据实现)。
布比
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.