如何获得EntityFrameworkCore生成的SQL以对DateTime对象使用正确的格式?

时间:2018-08-28 01:37:00

标签: c# sql-server entity-framework-core

我正在使用Microsoft.EntityFrameworkCore.SqlServer v2.1.2(并且还尝试过v2.2.0-preview1-35029),并且正在使用LINQ从Azure SqlServer数据库中获取实体集合,并在DateTime字段上进行过滤。

但是,LINQ语句生成的SQL使用基于字符串的DateTime值,SqlServer会由于以下错误而拒绝该值:

  

从字符串转换日期和/或时间时转换失败。

我可以修改SQL语句以更改日期时间格式,以使查询正常运行(请参见下文以了解详细信息),但是我不知道如何获取框架以生成相同的日期时间格式。

虽然EntityFrameworkCore仍然是一个新事物,但看来这是一个非常简单的用例,因此我假设我做错了什么,这不是框架问题。

如何防止EF在SQL中生成无效的datetime值?

和/或

如何获取生成的SQL以对DateTime对象使用另一种格式?


我正在使用的EntityFramework模型如下:

public class DeskReading
{
    public int DeskReadingId { get; set; }
    //... some other fields ...
    public DateTime Timestamp { get; set; }
}

我的LINQ查询值看起来像这样:

IQueryable<DeskReading> readings = 
    _dbContext.DeskReadings
            .OrderBy(gr => gr.Timestamp)
            .Where(gr => gr.Timestamp > new DateTime(2017, 05, 01));

readings.ToList();

生成的SQL看起来像这样:

SELECT [gr].[DeskReadingId] --...some other fields ...
FROM [DeskReadings] AS [gr]
WHERE [gr].[Timestamp] > '2017-05-01T00:00:00.0000000'
ORDER BY [gr].[Timestamp]

请注意,过滤器的值为'2017-05-01T00:00:00.0000000'

如果我通过SSMS直接在SqlServer上运行该SQL,则会收到相同的错误:

enter image description here

但是,如果我将过滤器更改为使用'2017-05-01 00:00:00',它将正常工作:

SELECT [gr].[DeskReadingId] --...some other fields ...
FROM [DeskReadings] AS [gr]
WHERE [gr].[Timestamp] > '2017-05-01 00:00:00'
ORDER BY [gr].[Timestamp]

根据要求,这是表的创建脚本:

CREATE TABLE [dbo].[DeskReadings](
    [DeskReadingId] [int] IDENTITY(1,1) NOT NULL,
    [SoilMoistureSensor1] [int] NOT NULL,
    [SoilMoistureSensor2] [int] NOT NULL,
    [LightLevel] [int] NOT NULL,
    [TemperatureF] [real] NOT NULL,
    [HumidityPercent] [real] NOT NULL,
    [Timestamp] [datetime] NOT NULL,
 CONSTRAINT [PK_dbo.DeskReadings] PRIMARY KEY CLUSTERED 
(
    [DeskReadingId] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

1 个答案:

答案 0 :(得分:2)

GitHub 上查看源代码时, EntityFrameworkCore 使用一种条件格式,该格式基于它认为表达式中的列为StoreType的StoreType。例如,您看到的格式显然是datetime2的格式。将datetime列与datetime2格式的字符串进行比较时,可能会出现您遇到的错误。

这里是我要引用的源,有三个字符串常量,它们代表C#DateTime值的格式:

    private const string DateFormatConst = "{0:yyyy-MM-dd}";
    private const string DateTimeFormatConst = "{0:yyyy-MM-ddTHH:mm:ss.fffK}";
    private const string DateTime2FormatConst = "{0:yyyy-MM-ddTHH:mm:ss.fffffffK}";

格式 https://github.com/aspnet/EntityFrameworkCore/blob/release/2.2/src/EFCore.SqlServer/Storage/Internal/SqlServerDateTimeTypeMapping.cs#L18-L20

条件逻辑 https://github.com/aspnet/EntityFrameworkCore/blob/release/2.2/src/EFCore.SqlServer/Storage/Internal/SqlServerDateTimeTypeMapping.cs#L70-L74

要解决此特定问题,您可以将模型归为这样:

public class DeskReading
{
    public int DeskReadingId { get; set; }

    [Column(TypeName="datetime")]
    public DateTime Timestamp { get; set; }
}

这将迫使比较将其视为StoreType的{​​{1}},并正确设置其格式。