在 LINQ 查询中使用 DateTime 比较时,“LINQ 表达式无法转换”?

6

我是一个新手,最近开始使用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://learn.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方法:

enter image description here

同样适用于EF.Functions(没有公共方法): 在此输入图片描述 这可能是一个错误,还是我没有正确使用这些类?这是我想要实现的正确方法吗? 干杯!

它们是扩展方法,但您缺少导入,请尝试添加 using Microsoft.EntityFrameworkCore; - DavidG
@DavidG 我的类顶部已经添加了该导入。 - K. Vu
请确保您已经安装了 Microsoft.EntityFrameworkCore.SqlServer 包。 - Svyatoslav Danyliv
你是否缺少 Microsoft.EntityFrameworkCore.SqlServer 包? - DavidG
2个回答

9
如果时间组件是静态的(对所有行都相同),那么一个简单的选项是将其应用于当前日期以形成一个截止日期进行比较:
而不是:
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比较。 - K. Vu
1
我已经更新了我的示例。对于来自数据的动态表达式,DateTime 方法(如 AddHours)将通过 EF 进行翻译。 - Steve Py

3

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接