【问题标题】:EF DateTime formattingEF 日期时间格式
【发布时间】:2019-01-28 22:05:37
【问题描述】:

我首先使用 EF 6 代码,需要在特定格式的 dateTime 上执行 sql,例如:

我的第一次尝试是这样的:

var users = context.User
       .Where(x => x.BirthDate.ToString("dd/MMM/yyyy h:mm tt").Contains(searchTerm).ToList()

抛出异常,因为 EF 不知道如何将 DateTime.ToString() 转换为 SQL,这是有道理的。

到目前为止,我发现的最佳解决方案来自此页面:Entity Framework 6 ToString(), formatting (DateTime format), query intercept,其中回答者使用以下函数:SqlFunctions.DatePartDbFunctions.Right 生成一个字符串,EF 可以执行 Contains 但是对于我场景我特别需要格式为"dd/MMM/yyyy hh:mm tt"(2017 年 1 月 20 日上午 8 点 22 分),此时我正努力以 MMM 格式度过一个月。

附带说明,如果有另一种方法可以通过创建我自己的从 DbFunctionsSqlFunctions 类扩展的函数来实现这一点,这也可以解决问题。

【问题讨论】:

  • 我建议您使用TryParseExact 转换您的输入日期,并在您的查询过滤器中使用生成的DateTime 变量

标签: c# entity-framework linq datetime iqueryable


【解决方案1】:

要以MMM 格式获取月份,您可以使用:

DbFunctions.Left(SqlFunctions.DateName("month", x.BirthDate),3)

最终查询可能如下所示:

var users = context.User
   .Where(x =>
        (DbFunctions.Right("0" + SqlFunctions.DatePart("d", x.BirthDate), 2) + "/" //day
            + DbFunctions.Left(SqlFunctions.DateName("month", x.BirthDate), 3) + "/" // month
            + SqlFunctions.DatePart("yyyy", x.BirthDate) + " "
            + DbFunctions.Right("0" + (x.BirthDate.Hour > 12 ? x.BirthDate.Hour % 12 : x.BirthDate.Hour).ToString(), 2) + ":"
            + DbFunctions.Right("0" + SqlFunctions.DatePart("mi", x.BirthDate), 2) + " "
            + (x.BirthDate.Value.Hour > 11 ? "PM" : "AM"))
        .Contains(searchTerm)
    ).ToList();

但我担心性能。

【讨论】:

    【解决方案2】:

    如果以特定格式搜索日期列很重要,那么我建议将计算列添加到表中以将日期/时间显示为字符串。像这样的解决方案需要注意的是性能。对于较小到中等大小的表/数据库,这将是可以接受的,但您需要监控性能并避免将此类技术用作拐杖,因为随着系统的增长,它可能会反过来咬您。

    ALTER TABLE Users
    ADD COLUMN FormattedBirthDate AS formatDate(BirthDate)
    

    formatDate 是一个标量函数:

    CREATE FUNCTION formatDate 
    (
        @dateTime AS DateTime
    )
    RETURNS VARCHAR(50)
    AS
    BEGIN
        DECLARE @result AS VARCHAR(50)
    
        IF @dateTime IS NULL
          RETURN NULL
    
        SELECT @result = CAST(DATEPART(dd, @dateTime) AS VARCHAR) + '/' + LEFT(DATENAME(MONTH, @dateTime),3) + '/' + CAST(YEAR(@dateTime) AS VARCHAR) + ' ' + CAST(DATEPART(HOUR, @dateTime) - (12 * CEILING((DATEPART(HOUR, @dateTime) - 12)*.1)) AS VARCHAR(2)) + ':' + RIGHT('00' + CAST(DATEPART(MINUTE,@dateTime) AS VARCHAR(2)),2) + ' ' + CASE WHEN DATEPART(HOUR,@dateTime) >= 12 THEN 'PM' ELSE 'AM' END
        RETURN @result
    
    END
    

    这会根据您指定的内容应用静态格式。难读,可能有一些优化。

    这会公开一个名为 FormattedBirthDate 的新列,您可以在 EF 中映射该列,尽管您需要采取措施确保将其视为只读列,并将其识别为计算列。我不会在 ViewModels 等中返回它,仅用于您的搜索。

    在用户实体中:

    public string FormattedBirthDate { get; private set;}
    

    在用户实体类型配置中:

    Property(x => x.FormattedBirthDate)
        .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
    

    这将确保在保存对出生日期的更改后刷新实体的格式化出生日期。所以需要注意的是,如果您更改出生日期,格式化的出生日期将与出生日期匹配,直到调用 SaveChanges。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-10
      • 1970-01-01
      相关资源
      最近更新 更多