我有一个非常简单的SQL Server数据库表,其中包含datetime
主键:
我为此表生成了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类型一起使用?
答案 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");
}