为了账号安全,请及时绑定邮箱和手机立即绑定

LINQ where 子句中的 DateTime 属性错误

LINQ where 子句中的 DateTime 属性错误

C#
尚方宝剑之说 2022-12-24 10:25:36
我有一个非常简单的方法,它使用一些 LINQ 来访问我的数据库中的数据。我有一些项目正在存储它们的创建日期。日期包括一个偏移量,因此它在数据库中存储为 datetimeoffset 类型。我正在尝试按日期过滤项目,为此我需要减去偏移时间来比较它们:public async Task<IEnumerable<Item>> GetItems(DateTime? startDate){    var items = _dbContext.Items                                                        .AsQueryable();    if (startDate != null)    {        items = items.Where(i =>            i.DateCreated.DateTime.AddHours(i.DateCreated.Offset.Hours) >= startDate.Value);    }    return await items                     .ToListAsync();}但是当ToListAsync()被调用时,我得到这个错误:因警告“Microsoft.EntityFrameworkCore.Query.QueryClientEvaluationWarning:LINQ 表达式‘where ([e].DateCreated.DateTime.AddHours(Convert([e].DateCreated.Offset.Hours, Double)) >= __startDate_Value_0)”而生成错误不被翻译,将在当地进行评估。'。通过将事件 ID“RelationalEventId.QueryClientEvaluationWarning”传递给“DbContext.OnConfiguring”或“AddDbContext”中的“ConfigureWarnings”方法,可以抑制或记录此异常。问题似乎出在AddHours方法上,如果我把它去掉,它就可以正常工作。但我不知道是否有办法在不使用该方法的情况下使它工作。我可以在这里使用不同的策略吗?
查看完整描述

2 回答

?
翻翻过去那场雪

TA贡献2065条经验 获得超14个赞

实际上支持DateTime.AddHours方法的翻译。


问题是目前 EF Core 无法翻译 的大部分(如果不是全部)成员DateTimeOffset,在这种特殊情况下 -DateTime属性(与 等相同Offset)DateTimeUtc。


幸运的是它确实支持DateTimeOffset比较的转换,所以解决方案是换一种方式——将DateTime参数转换为DateTimeOffset并在查询中进行简单的比较,例如


if (startDate != null)

{

    // Note: must be a variable outside the query expression tree

    var startDateOffset = new DateTimeOffset(startDate.Value);

    items = items.Where(i => i.DateCreated >= startDateOffset);

}


查看完整回答
反对 回复 2022-12-24
?
慕侠2389804

TA贡献1719条经验 获得超6个赞

更新的答案(EF Core):

根据此链接DbFunctionsEF Core 当前不支持。

如果您想AddHour使用 EF Core 进行调用,一种选择是AddHour在您的数据库中定义为标量函数,然后您可以在您的 LINQ 查询中调用它。

本文档解释了如何完成:

在您的 DbContext 上声明一个静态方法并使用以下注释对其进行注释DbFunctionAttribute

public class MyDbContext : DbContext

{

    [DbFunction]

    public static int AddHours(DataTime source, int hours)

    {

        // you don't need any implementation 

        throw new Exception(); 

    }

}

像这样的方法会自动注册。注册后,对 LINQ 查询中的方法的调用可以转换为 SQL 中的函数调用:


items = items.Where(i =>

    MyDbContext.AddHours(i.DateCreated, i.DateCreated.Offset.Hours) >= startDate.Value);

免责声明:我个人不喜欢这个解决方案。编写一个新方法,只是为了抛出一个异常,远不是一个优雅的设计。不幸的是,如果您想使用 EF Core,您没有太多选择。


原始答案(EF 4/5/6):

AddHour不是您数据库中的函数。它需要被翻译成数据库中相应的功能。


如果您使用的是 SQL Server,那么您可以使用这段代码,它将转换AddHour为相应的 DB 函数:


items = items.Where(i =>

    DbFunctions.AddHour(i.DateCreated, i.DateCreated.Offset.Hours) >= startDate.Value);

如果您不使用 SQL Server,那么您需要AddHour在您的数据库中定义函数,定义后您可以使用DbFunctions.AddHour, 来调用它。


查看完整回答
反对 回复 2022-12-24
  • 2 回答
  • 0 关注
  • 100 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信