【问题标题】:How to fix the datetime2 out-of-range conversion error using DbContext and SetInitializer?如何使用 DbContext 和 SetInitializer 修复 datetime2 超出范围的转换错误?
【发布时间】:2011-08-28 09:33:48
【问题描述】:

我正在使用 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 数据的转换 类型为日期时间数据类型导致 在一个超出范围的值。这 语句已终止。

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

有什么想法吗?

【问题讨论】:

  • 您可以使用 SQL Profiler 查看插入/更新 SQL 语句吗?很难说这里发生了什么 - 我们看不到您的初始化程序或实体。 SQL Profiler 将极大地帮助您定位问题。
  • 在我的例子中,我在表格中添加了一个字段并编辑了表单,忘记更新绑定包含并且我的字段被设置为 NULL。所以这个错误帮助纠正了我的疏忽。

标签: c# .net entity-framework ef-code-first dbcontext


【解决方案1】:

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

【讨论】:

  • 我的一些初始化器对象没有设置日期,所以它会默认为 DateTime.MinValue。
  • 我也这样做了^。向 asp.net 标识 ApplicationUser 对象添加了一个自定义日期字段,然后忘记将其初始化为有意义的内容。 : (
  • 在我的例子中,问题出在最小日期,01/01/0001 产生了错误。
  • 如何检查 dateTime.minvalue ?
  • 有点晚了,但是@Anabeil 你应该可以在 VS/linqpad 的即时窗口中只使用 Console.WriteLine(DateTime.MinValue)
【解决方案2】:

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

.HasColumnType("datetime2")

【讨论】:

    【解决方案3】:

    在某些情况下,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();
    

    【讨论】:

      【解决方案4】:

      在构造函数中初始化 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; }
          }
      

      【讨论】:

        【解决方案5】:

        尽管这个问题已经很老了,并且已经有了很好的答案,但我认为我应该再提出一个来解释解决这个问题的 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 -note? 之后DateTime-

        public virtual DateTime? Start { get; set; }
        

        更多解释请阅读post

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            【解决方案7】:

            简单。 首先在您的代码上,将 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; }
                }
            

            【讨论】:

            • 并非总是如此。 {1/1/0001 12:00:00 AM} 也会出现此错误
            【解决方案8】:

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

            【讨论】:

              【解决方案9】:

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

              【讨论】:

                【解决方案10】:

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

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

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

                【讨论】:

                  【解决方案11】:

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

                  【讨论】:

                    【解决方案12】:

                    根据用户 @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的评论

                    【讨论】:

                      【解决方案13】:

                      一行解决了这个问题:

                      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 部分应该可以工作。

                      【讨论】:

                        【解决方案14】:

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

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

                        【讨论】:

                          【解决方案15】:

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

                          【讨论】:

                            猜你喜欢
                            • 1970-01-01
                            • 2015-01-11
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2021-05-30
                            • 1970-01-01
                            • 2023-04-09
                            相关资源
                            最近更新 更多