140

我正在使用 Entity Framework 4.1 引入的 DbContext 和 Code First API。

数据模型使用基本数据类型,例如stringDateTime。在某些情况下,我使用的唯一数据注释是[Required],但这不在任何DateTime属性上。例子:

public virtual DateTime Start { get; set; }

DbContext子类也很简单,如下所示:

public class EventsContext : DbContext
{
    public DbSet<Event> Events { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Event>().ToTable("Events");
    }
}

初始化程序将模型中的日期设置为今年或明年的合理值。

但是,当我运行初始化程序时,我在以下位置收到此错误context.SaveChanges()

将 datetime2 数据类型转换为 datetime 数据类型导致值超出范围。该语句已终止。

我不明白为什么会发生这种情况,因为一切都那么简单。我也不确定如何修复它,因为没有要编辑的 edmx 文件。

有任何想法吗?

4

15 回答 15

194

您必须确保 Start 大于或等于 SqlDateTime.MinValue(1753 年 1 月 1 日) - 默认情况下 Start 等于 DateTime.MinValue(0001 年 1 月 1 日)。

于 2011-05-18T21:12:11.793 回答
24

简单的。首先在您的代码上,将 DateTime 的类型设置为 DateTime?。因此,您可以在数据库中使用可为空的 DateTime 类型。实体示例:

public class Alarme
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }

        public DateTime? DataDisparado { get; set; }//.This allow you to work with nullable datetime in database.
        public DateTime? DataResolvido { get; set; }//.This allow you to work with nullable datetime in database.
        public long Latencia { get; set; }

        public bool Resolvido { get; set; }

        public int SensorId { get; set; }
        [ForeignKey("SensorId")]
        public virtual Sensor Sensor { get; set; }
    }
于 2015-05-11T16:27:05.653 回答
23

在某些情况下,DateTime.MinValue(或等效地,default(DateTime))用于指示未知值。

这种简单的扩展方法可以帮助处理这种情况:

public static class DbDateHelper
{
    /// <summary>
    /// Replaces any date before 01.01.1753 with a Nullable of 
    /// DateTime with a value of null.
    /// </summary>
    /// <param name="date">Date to check</param>
    /// <returns>Input date if valid in the DB, or Null if date is 
    /// too early to be DB compatible.</returns>
    public static DateTime? ToNullIfTooEarlyForDb(this DateTime date)
    {
        return (date >= (DateTime) SqlDateTime.MinValue) ? date : (DateTime?)null;
    }
}

用法:

 DateTime? dateToPassOnToDb = tooEarlyDate.ToNullIfTooEarlyForDb();
于 2013-10-25T07:42:43.717 回答
13

尽管这个问题已经很老了,并且已经有了很好的答案,但我想我应该再放一个来解释解决这个问题的 3 种不同方法。

第一种方法

DateTime将属性显式映射public virtual DateTime Start { get; set; }datetime2表中的相应列。因为默认情况下 EF 会将其映射到datetime.

这可以通过 fluent API 或数据注释来完成。

  1. 流畅的 API

    在 DbContext 类中覆盖OnModelCreating和配置属性Start(出于解释原因,它是 EntityClass 类的属性)。

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Configure only one property 
        modelBuilder.Entity<EntityClass>()
            .Property(e => e.Start)
            .HasColumnType("datetime2");
    
       //or configure all DateTime Preperties globally(EF 6 and Above)
        modelBuilder.Properties<DateTime>()
            .Configure(c => c.HasColumnType("datetime2"));
    }
    
  2. 数据标注

    [Column(TypeName="datetime2")]
    public virtual DateTime Start { get; set; }
    

第二种方法

在 EntityClass 构造函数中初始化Start为默认值。这很好,就好像由于某种原因在Start将实体保存到数据库开始之前未设置的值将始终具有默认值一样。确保默认值大于或等于SqlDateTime.MinValue(从 1753 年 1 月 1 日到 9999 年 12 月 31 日)

public class EntityClass
{
    public EntityClass()
    {
        Start= DateTime.Now;
    }
    public DateTime Start{ get; set; }
}

第三种方法

使其Start成为可为空的类型-DateTime 注意 -?DateTime

public virtual DateTime? Start { get; set; }

更多解释请阅读这篇文章

于 2015-01-21T11:37:30.097 回答
13

如果适合您的特定建模问题,您可以使该字段为空。不会像默认值那样将空日期强制转换为不在 SQL DateTime 类型范围内的日期。另一种选择是显式映射到不同的类型,也许是,

.HasColumnType("datetime2")
于 2011-05-19T04:36:58.127 回答
8

如果您的DateTime属性在数据库中可以为空,那么请务必使用DateTime?关联的对象属性,否则 EF 将传入DateTime.MinValueSQL 日期时间类型可以处理的范围之外的未分配值。

于 2015-01-27T18:47:41.997 回答
8

我的解决方案是将所有日期时间列切换到 datetime2,并将 datetime2 用于任何新列。换句话说,让 EF 默认使用 datetime2。将此添加到上下文的 OnModelCreating 方法中:

modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));

那会得到所有的DateTime和DateTime吗?您所有实体的属性。

于 2016-08-29T10:37:26.320 回答
3

在构造函数中初始化 Start 属性

Start = DateTime.Now;

当我尝试使用 Code First 向 ASP .Net Identity Framework 的用户表 (AspNetUsers) 添加一些新字段时,这对我有用。我更新了 IdentityModels.cs 中的类 - ApplicationUser,并添加了一个 DateTime 类型的字段 lastLogin。

public class ApplicationUser : IdentityUser
    {
        public ApplicationUser()
        {
            CreatedOn = DateTime.Now;
            LastPassUpdate = DateTime.Now;
            LastLogin = DateTime.Now;
        }
        public String FirstName { get; set; }
        public String MiddleName { get; set; }
        public String LastName { get; set; }
        public String EmailId { get; set; }
        public String ContactNo { get; set; }
        public String HintQuestion { get; set; }
        public String HintAnswer { get; set; }
        public Boolean IsUserActive { get; set; }

        //Auditing Fields
        public DateTime CreatedOn { get; set; }
        public DateTime LastPassUpdate { get; set; }
        public DateTime LastLogin { get; set; }
    }
于 2014-08-09T17:16:08.273 回答
2

根据用户@andygjp 的回答,如果您覆盖基本Db.SaveChanges()方法并添加一个函数来覆盖任何不在 SqlDateTime.MinValue 和 SqlDateTime.MaxValue 之间的日期,则效果会更好。

这是示例代码

public class MyDb : DbContext
{
    public override int SaveChanges()
    {
        UpdateDates();
        return base.SaveChanges();
    }

    private void UpdateDates()
    {
        foreach (var change in ChangeTracker.Entries().Where(x => (x.State == EntityState.Added || x.State == EntityState.Modified)))
        {
            var values = change.CurrentValues;
            foreach (var name in values.PropertyNames)
            {
                var value = values[name];
                if (value is DateTime)
                {
                    var date = (DateTime)value;
                    if (date < SqlDateTime.MinValue.Value)
                    {
                        values[name] = SqlDateTime.MinValue.Value;
                    }
                    else if (date > SqlDateTime.MaxValue.Value)
                    {
                        values[name] = SqlDateTime.MaxValue.Value;
                    }
                }
            }
        }
    }
}

取自用户 @sky-dev 对https://stackoverflow.com/a/11297294/9158120的评论

于 2019-02-18T10:30:38.757 回答
1

我遇到了同样的问题,在我的情况下,我将日期设置为 new DateTime() 而不是 DateTime.Now

于 2016-03-25T20:06:56.220 回答
0

我使用的是 Database First,当这个错误发生在我身上时,我的解决方案是在 edmx 文件中强制 ProviderManifestToken="2005" (使模型与 SQL Server 2005 兼容)。不知道 Code First 是否有类似的可能。

于 2017-04-07T20:55:05.927 回答
0

一行解决了这个问题:

modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));

因此,在我的代码中,我添加了:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));
}

将这一行添加到 DBContext 子类覆盖 void OnModelCreating 部分应该可以工作。

于 2019-06-04T12:50:59.767 回答
0

就我而言,在 EF6 中进行了一些重构后,我的测试失败并显示与原始海报相同的错误消息,但我的解决方案与 DateTime 字段无关。

创建实体时,我只是缺少一个必填字段。一旦我添加了缺失的字段,错误就消失了。我的实体确实有两个 DateTime?领域,但他们不是问题。

于 2019-07-29T18:20:46.690 回答
0

在我的情况下,当我使用实体并且 sql 表具有 datetime == getdate() 的默认值时,就会发生这种情况。所以我做了什么来为这个字段设置一个值。

于 2016-02-27T20:50:24.100 回答
-1

如果有人像我一样愚蠢,请仔细检查您约会的年份。我正在从 YYMMDD 格式的文本文件中转换日期,因此正在创建一个年份为 0020 的日期,而不是 2020 年。明显的错误,但我花了更多时间查看它,但没有看到它比我应该看到的!

于 2020-12-02T10:25:04.073 回答