【问题标题】:"LINQ expression could not be translated" with DateTime comparison in LINQ query?“无法翻译 LINQ 表达式”与 LINQ 查询中的 DateTime 比较?
【发布时间】:2021-03-01 09:44:53
【问题描述】:

我是刚开始在项目中使用 EF Core 5 的新手,遇到以下查询问题:

TimeSpan bookTimeToLive = TimeSpan.FromHours(10);
IList<Book>? expiredBooks = dbContext.Value.Books.AsQueryable()
                    .Where(x => DateTime.UtcNow - x.UtcTimeStamp > bookTimeToLive)
                    .ToList();

// Get list of expired Books to remove them
dbContext.Value.RemoveRange(expiredBooks);
await dbContext.Value.SaveChangesAsync(cancellationToken);

我的目标是删除所有过期的图书(它们的时间戳超过了我想要跟踪它们的时间)。

这样,我得到了例外:

The LINQ expression 'DbSet<Books>()
    .Where(d => DateTime.UtcNow - d.UtcTimeStamp > __bookTimeToLive_0)' could not be translated. Either
 rewrite the query in a form that can be translated, or switch to client evaluation explicitly by 
inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See 
https://go.microsoft.com/fwlink/?linkid=2101038 for more information.

经过一番挖掘,我意识到这是因为 EF 无法将我的 DateTime 比较解析为 SQL 查询,所以我尝试使用 https://docs.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.sqlserverdbfunctionsextensions.datediffhour?view=efcore-5.0#Microsoft_EntityFrameworkCore_SqlServerDbFunctionsExtensions_DateDiffHour_Microsoft_EntityFrameworkCore_DbFunctions_System_DateTime_System_DateTime_ 中的 DbFunctions.DateDiffHour() 方法

现在的问题是,即使我在课堂上安装并导入了 Nuget EF Core 5,我也无法访问任何 DbFunctions 方法:

这同样适用于 EF.Functions(没有公共方法):

这可能是一个错误还是我没有正确使用这些类?这是我想要完成的正确方法吗? 干杯!

【问题讨论】:

  • 它们是扩展方法,但您缺少导入,请尝试添加using Microsoft.EntityFrameworkCore;
  • @DavidG 导入已添加到我的班级顶部
  • 确保你已经安装了包Microsoft.EntityFrameworkCore.SqlServer

标签: c# entity-framework entity-framework-core entity-framework-5


【解决方案1】:

如果时间组件是静态的(所有行都相同),那么一个简单的选择是将其应用于当前日期以形成一个截止值以进行比较:

代替:

TimeSpan bookTimeToLive = TimeSpan.FromHours(10);
IList<Book> expiredBooks = dbContext.Value.Books
                .Where(x => DateTime.UtcNow - x.UtcTimeStamp > bookTimeToLive)
                .ToList();

类似的东西。不需要 DbFunctions。

DateTime expiryCutoff = DateTime.UtcNow.AddHours(-10);
Ilist<Book> expiredBooks = dbContext.Books
    .Where(x => x.UtTimeStamp < expiryCutoff)
    .ToList();

如果它是动态的,DateTime 像 AddHours 这样的方法仍然会翻译:

Ilist<Book> expiredBooks = dbContext.Books
    .Where(x => x.UtTimeStamp.AddHours(x.ExpiryCutoff) < DateTime.UtcNow)
    .ToList();

其中 ExpiryCutoff 是记录中的数据驱动值。 (或相关表达)

【讨论】:

  • 每行的时间戳组件不同,因此我需要一种更“动态”的方式来执行 DateTime 比较
  • 我已经更新了我的示例。对于来自数据的动态表达式,DateTime 方法如 AddHours 将通过 EF 进行转换。
【解决方案2】:

或者,我们可以只使用DateTime 对象并重写您的原始查询吗?

IList<Book>? expiredBooks = dbContext.Value.Books
                    .Where(x => x.UtcTimeStamp.addHours(10) > DateTime.UtcNow)
                    .ToList();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-28
    • 1970-01-01
    • 2022-12-03
    • 2021-05-28
    • 2021-10-13
    • 2021-07-26
    • 1970-01-01
    相关资源
    最近更新 更多