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

问题描述 投票:126回答:13

我正在使用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文件可以编辑。

有任何想法吗?

c# .net entity-framework ef-code-first dbcontext
13个回答
181
投票

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


1
投票

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


0
投票

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


0
投票

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


0
投票

一行解决了这个问题:

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;
                    }
                }
            }
        }
    }
}

所以,在我的代码中,我补充说:

https://stackoverflow.com/a/11297294/9158120

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


0
投票

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

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


21
投票

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

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;
    }
}

用法:

 DateTime? dateToPassOnToDb = tooEarlyDate.ToNullIfTooEarlyForDb();

13
投票

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

.HasColumnType("datetime2")

11
投票

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

第一种方法

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

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

  1. 流畅的API 在DbContext类中,重写qazxsw poi并配置属性qazxsw poi(出于解释原因,它是EntityClass类的属性)。 OnModelCreating
  2. 数据注释 Start

第二种方法

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")); } 初始化为EntityClass构造函数中的默认值。这很好,好像由于某种原因在将实体保存到数据库之前未设置[Column(TypeName="datetime2")] public virtual DateTime Start { get; set; } 的值,start将始终具有默认值。确保默认值大于或等于Start(从1753年1月1日到9999年12月31日)

Start

第三种方法

SqlDateTime.MinValue-之后使public class EntityClass { public EntityClass() { Start= DateTime.Now; } public DateTime Start{ get; set; } } 成为可以为空的Start -note DateTime

?

有关更多解释,请阅读此DateTime


8
投票

如果您的public virtual DateTime? Start { get; set; } 属性在数据库中可以为空,那么请务必使用post作为关联的对象属性,否则EF将在DateTime中传递未分配的值,这些值超出了SQL日期时间类型可以处理的范围。


8
投票

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

DateTime?

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


3
投票

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

DateTime.MinValue

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

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

2
投票

基于user @ andygjp的答案,如果你覆盖基本的Start = DateTime.Now; 方法并添加一个函数来覆盖任何不在SqlDateTime.MinValue和SqlDateTime.MaxValue之间的日期,它会更好。

这是示例代码

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; }
    }

取自用户@ sky-dev对Db.SaveChanges()的评论

© www.soinside.com 2019 - 2024. All rights reserved.