在Code-First Entity Framework和SQL Server中使用DateTime属性

33

我有一个示例类book

public class Book
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime DateAdded { get; set; }
}

当我试图向BookDb上下文中添加一个新的book时...

using (BookDb db = new BookDb())
{
    Book book = new Book {
        Name = "Some name",
        DateAdded = DateTime.Now
    };

    db.Books.Add(book);
    db.SaveChanges();
}

出现了错误:

System.Data.SqlClient.SqlException: 将datetime2数据类型转换为datetime数据类型时,结果超出范围。语句已终止。


我发现原因是.NET和SQL Server之间不兼容的datetime类型。在传统的Entity Framework中,有一种方法可以告诉EF使用SQL Server的格式,但是Code-First Entity Framework中该怎么做呢?

我正在使用EF4和.NET 4(MVC 3 Web应用程序)以及SQL Server 2008 Express。


2
你把电脑的时钟设置成了类似于1750年或更早的时间吗? - Slauma
11
我不是认真的 :) 请看我的回答。 - Slauma
4个回答

53

您可以在Fluent API中指定类型:

modelBuilder.Entity<Book>()
    .Property(f => f.DateTimeAdded)
    .HasColumnType("datetime2");

这将在数据库中创建一个datetime2(7)列。如果您想要微调精度,可以使用:

modelBuilder.Entity<Book>()
    .Property(f => f.DateTimeAdded)
    .HasColumnType("datetime2")
    .HasPrecision(0);

然而,你在问题中展示的代码是有效的,因为datetime类型允许存储日期回到大约1750年。异常仅在更早的日期发生。这种异常的常见原因是DateTime属性未初始化,因为它表示无法存储在SQL Server的datetime列中的0001年。

没有相应的数据注释属性来定义这个问题,只能通过Fluent API实现。


在我的代码示例中,DateAdded属性没有正确初始化吗? - Chad Levy
1
@Paperjam: 是的,但这是否是您已测试过的确切代码,或者您的测试模型中可能有另一个未初始化的DateTime属性?如果没有,那么这很奇怪。我经常使用datetime列,并且使用Now初始化DateTime属性从来没有问题。昨天我测试了您的示例以再次证明自己,并且它没有引发异常。 - Slauma
1
糟糕!是的,我有一个未初始化的属性。我想我会开始我的存储库模式模型,以避免这样的愚蠢错误。谢谢你的帮助!我一定会更多地了解流畅API。 - Chad Levy
请注意,EF版本4.3.1添加了一些修复程序。有关详细信息,请参阅此帖子:https://dev59.com/NmDVa4cB1Zd3GeqPhur6 - Designpattern
1
注释确实有效!不需要使用模型构建器。 - user1029883

32

在保存日期时,必须填入一个值。这就是为什么会出现此错误。

只需使用 DateTime?。上面的魔法是不必要的。


在我的示例代码中,当我初始化一个新的“Book”类时,我将“DateAdded”设置为“DateTime.Now”。这个值不是有效地填充了吗?或者我有什么遗漏了吗? - Chad Levy
转念一想,实际上是这样的。我记得我遇到的问题是关于我的仓库代码,其中“DateAdded”实际上没有被设置。使用可空字段虽然有助于防止我的疏忽引发错误,但不符合我的应用程序的要求。感谢您提出的好建议! - Chad Levy
2
如果您的模型需要可空类型,请使用可空类型,但如果不需要,则不应该仅为了使种子或其他初始化程序正常工作而使用它。 - RickAndMSFT
如果我不想将其设置为可空类型,那么我所指的是项目要求不考虑此字段可空。 - Ashish-BeJovial

31

你可以使用 type datetime2 对你的类的属性进行注释。

public class Book
{
    [Column(TypeName = "datetime2")]
    public DateTime DateAdded { get; set; }
}

smalldatetime 也可以使用。 - Arun Prasad E S

2
如果启用了迁移,您还可以在此处调整设置。
public override void Up()
{
    CreateTable(
        "dbo.MyTable",
        c => new
        {
            Date = c.DateTime(false, 7, storeType: "datetime2"),
        });
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接