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

Ale*_*gas 132 .net c# entity-framework ef-code-first dbcontext

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

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

public virtual DateTime Start { get; set; }
Run Code Online (Sandbox Code Playgroud)

的DbContext子类也很简单,看起来像:

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

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Event>().ToTable("Events");
    }
}
Run Code Online (Sandbox Code Playgroud)

初始化设置日期在模型中有意义的值在今年或明年.

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

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

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

有任何想法吗?

小智 183

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

  • 我留下了一些没有设置日期的初始化程序对象,所以它默认为DateTime.MinValue. (14认同)

小智 22

简单.首先在代码中,将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; }
    }
Run Code Online (Sandbox Code Playgroud)

  • 情况并非总是如此.{1/1/0001 12:00:00 AM}也会出现此错误 (6认同)

Kja*_*tan 19

在某些情况下,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;
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

 DateTime? dateToPassOnToDb = tooEarlyDate.ToNullIfTooEarlyForDb();
Run Code Online (Sandbox Code Playgroud)


Bri*_*ler 13

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

.HasColumnType("datetime2")
Run Code Online (Sandbox Code Playgroud)


AIM*_*AIM 12

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

第一种方法

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

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

  1. 流畅的API

    在DbContext类中包含over OnModelCreating和configure属性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"));
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 数据注释

    [Column(TypeName="datetime2")]
    public virtual DateTime Start { get; set; }
    
    Run Code Online (Sandbox Code Playgroud)

第二种方法

初始化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; }
}
Run Code Online (Sandbox Code Playgroud)

第三种方法

使之Start成为可以为空的类型DateTime -note ? after DateTime-

public virtual DateTime? Start { get; set; }
Run Code Online (Sandbox Code Playgroud)

有关更多说明,请阅读此文章


Chr*_*ing 8

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


Ogg*_*las 8

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

modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));
Run Code Online (Sandbox Code Playgroud)

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