首页 文章

如何使用DbContext和SetInitializer修复datetime2超出范围的转换错误?

提问于
浏览
121

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

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

public virtual DateTime Start { get; set; }

DbContext subclass 也很简单,看起来像:

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

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

initializer 将模型中的日期设置为今年或明年的合理值 .

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

将datetime2数据类型转换为日期时间数据类型会导致超出范围的值 . 该语句已终止 .

我不明白为什么会发生这种情况,因为一切都很简单 . 我也不确定如何解决它,因为没有edmx文件可以编辑 .

有任何想法吗?

11 回答

  • 6

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

  • 0

    简单 . 首先在代码中,将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; }
        }
    
  • 11

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

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

    .HasColumnType("datetime2")
    
  • 19

    虽然这个问题已经很老了,并且已经有了很好的答案,但我认为我应该再提一个解释这个问题的3种不同方法 .

    1st Approach

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

    这可以通过流畅的API或数据注释来完成 .

    • Fluent 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"));
    }
    
    • 数据注释
    [Column(TypeName="datetime2")]
    public virtual DateTime Start { get; set; }
    

    2nd Approach

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

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

    3rd Approach

    使 Start 成为可以为空的 DateTime -note ? DateTime 之后 -

    public virtual DateTime? Start { get; set; }
    

    如需更多解释,请阅读post

  • 8

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

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

    这将获得所有DateTime和DateTime?所有实体的属性 .

  • 173

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

  • 20

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

    Start = DateTime.Now;
    

    当我尝试使用Code First向ASP .Net Identity Framework的Users表(AspNetUsers)添加一些新字段时,这对我有用 . 我在IdentityModels.cs中更新了Class - 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; }
        }
    
  • 0

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

  • 12

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

  • 3

    我正在使用Database First,当我发生这个错误时,我的解决方案是在edmx文件中强制使用ProviderManifestToken =“2005”(使模型与SQL Server 2005兼容) . 不知道Code First是否有类似的东西 .

相关问题