如何使用DbContext和SetInitializer修复datetime2超出范围的转换错误?
我正在使用entity framework4.1中引入的DbContext和Code First API。
数据模型使用基本数据types,如string
和DateTime
。 我在某些情况下使用的唯一数据注释是[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"); } }
初始化程序将模型中的date设置为今年或明年的明智值。
但是,当我运行初始化,我得到这个错误在context.SaveChanges()
:
将datetime2数据types转换为date时间数据types会导致超出范围的值。 该语句已终止。
我不明白为什么会发生这种情况,因为一切都很简单。 我也不知道如何解决这个问题,因为没有edmx文件来编辑。
有任何想法吗?
您必须确保Start大于或等于SqlDateTime.MinValue(1753年1月1日) – 默认情况下,Start等于DateTime.MinValue(0001年1月1日)。
简单。 在您的代码中,将DateTime的types设置为DateTime ?. 所以你可以在数据库中使用可空的DateTimetypes。 实体示例:
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; } }
在某些情况下, 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();
如果适合您的具体build模问题,可以将该字段设置为空。 空date不会被强制为不在SQL DateTime范围内的date键入默认值的方式。 另一个select是显式映射到一个不同的types,或许与,
.HasColumnType("datetime2")
我的解决scheme是将所有date时间列切换到datetime2,并使用datetime2任何新的列。 换句话说,使EF默认使用datetime2。 将其添加到您的上下文的OnModelCreating方法:
modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));
那会得到所有的DateTime和DateTime? 所有实体的属性。
尽pipe这个问题已经很老了,已经有了很好的答案,但我还是认为应该多解释一下这3个不同的方法来解决这个问题。
第一种方法
显式映射DateTime
属性public virtual DateTime Start { get; set; }
public virtual DateTime Start { get; set; }
public virtual DateTime Start { get; set; }
到datetime2
在表中相应的列中。 因为默认情况下EF会将其映射到datetime
。
这可以通过stream畅的API或数据注释来完成。
-
stream利的API
在DbContext类overide
OnModelCreating
和configuration属性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; }
第二种方法
在EntityClass构造函数中将Initialize初始化为一个默认值。这是很好的,因为如果由于某些原因,在将实体保存到数据库之前没有设置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; }
欲了解更多解释阅读这篇文章
如果你的DateTime
属性在数据库中是可以空的,那么一定要使用DateTime?
对于关联的对象属性或EF将在DateTime.MinValue
传递未分配的值,这些值在SQL datetimetypes可以处理的范围之外。
在构造函数中初始化Start属性
Start = DateTime.Now;
当我尝试使用Code First向ASP .Net Identity Framework的用户表(AspNetUsers)添加一些新字段时,这对我有用。 我更新了IdentityModels.cs中的Class – ApplicationUser,并添加了DateTimetypes的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; } }
我有同样的问题,在我的情况下,我将date设置为新的DateTime()而不是DateTime.Now
在我的情况下,这发生在我使用实体时,sql表的默认值是datetime == getdate()。 所以我做了什么来设置这个领域的价值。
我使用数据库优先,当这个错误发生在我身上时,我的解决scheme是强制ProviderManifestToken =“2005”edmx文件(使模型与SQL Server 2005兼容)。 不知道Code First是否有类似的情况。