查询datetime列时,EF生成的SQL查询返回空结果,但该记录存在于数据库

时间:2016-09-21 09:59:46

标签: c# .net sql-server entity-framework datetime

我有一个非常简单的SQL Server数据库表,其中包含datetime主键:

Table with datetime primary key

我为此表生成了EF模型和数据库上下文:

[Table("Test")]
public partial class Test
{
    public DateTime Id { get; set; }
    public int Value { get; set; }
}

public partial class Model : DbContext
{
    public Model() : base("name=Model") { }
    public virtual DbSet<Test> Test { get; set; }
    protected override void OnModelCreating(DbModelBuilder modelBuilder) { }
}

Id = 2016-09-21 15:20:01.003表格中有Test的记录。让我们尝试使用EF上下文读取该记录:

var data = context.Test
    .Where(o => o.Id == new DateTime(2016, 09, 21, 15, 20, 01, 003))
    .ToList();
Console.WriteLine(data.Count); // data.Count = 0 here!

即使存在具有此ID的数据库记录,EF也会返回0条记录。这是生成的EF SQL查询:

-- This query produces an empty result
SELECT 
  [Extent1].[Id] AS [Id], 
  [Extent1].[Value] AS [Value]
  FROM [dbo].[Test] AS [Extent1]
  WHERE convert(datetime2, '2016-09-21 15:20:01.0030000', 121) = [Extent1].[Id]

如您所见,EF将DateTime方法谓词中的Where值转换为datetime2 SQL类型。实际上,此查询返回一个空结果集。

如果我删除转换并将日期更改为匹配datetime类型格式(即删除尾随零),则查询将按预期工作:

-- This query returns existing record
SELECT 
  [Extent1].[Id] AS [Id], 
  [Extent1].[Value] AS [Value]
  FROM [dbo].[Test] AS [Extent1]
  WHERE [Extent1].[Id] = '2016-09-21 15:20:01.003' 

我了解将Id列的类型更改为datetime2可以解决问题(实际上,Microsoft recommends使用datetime2进行所有新开发。但我仍然很好奇,这种行为是实体框架中的错误还是设计?有没有办法让它与datetime底层SQL类型一起使用?

2 个答案:

答案 0 :(得分:1)

是的,这是设计的。

原因:如果您没有为datetime字段设置任何值,那么EF将发送1.1.0001作为默认值。使用SQL datetime处理 类型。这就是EF团队建议在SQL服务器上使用datetime2作为数据类型的原因。

EF核心的EF的最新版本不支持SQL Server 2005 ,但它支持2008和forward.Due与我上面提到的相同的原因。换句话说,SQL Server 2005上没有datetime2数据类型。

答案 1 :(得分:0)

首先,虽然DateTime 适合用作索引,但不推荐 将它们用作主键。其次,您可以尝试设置属性类型以避免转换:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<Test>()
        .Property(m => m.Id)
        .HasColumnType("datetime");
}