我正在使用Entity Framework 4.1中引入的DbContext和Code First API。
数据模型使用基本数据类型,例如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");
}
}
初始化程序将模型中的日期设置为今年或明年的合理值。
然而,当我运行初始化程序时,我在context.SaveChanges()
:
datetime2数据的转换 输入到日期时间数据类型 在超出范围的价值。该 声明已被终止。
我不明白为什么会发生这种情况,因为一切都很简单。我也不确定如何修复它,因为没有要编辑的edmx文件。
有什么想法吗?
答案 0 :(得分:179)
您必须确保Start大于或等于SqlDateTime.MinValue(1753年1月1日) - 默认情况下,Start等于DateTime.MinValue(0001年1月1日)。
答案 1 :(得分: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; }
}
答案 2 :(得分: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();
答案 3 :(得分:12)
如果符合您特定的建模问题,您可以将该字段设为可为空。空日期不会像默认值那样被强制转换为不在SQL DateTime类型范围内的日期。另一种选择是明确映射到不同的类型,可能使用
.HasColumnType("datetime2")
答案 4 :(得分:11)
即使这个问题已经很老了,而且已经有了很好的答案,我想我应该再提一个解释这个问题的3种不同方法。
第一种方法
在表格的相应列中明确地将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; }
第二种方法
将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; }
}
第3种方法
在Start
-
DateTime
类型为可为空?
-note DateTime
public virtual DateTime? Start { get; set; }
有关详细说明,请阅读此post
答案 5 :(得分:8)
我的解决方案是将所有日期时间列切换为datetime2,并将datetime2用于任何新列。换句话说,默认情况下,EF使用datetime2。将其添加到上下文中的OnModelCreating方法:
modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));
那将获得所有DateTime和DateTime?所有实体的属性。
答案 6 :(得分:7)
如果您的DateTime
属性在数据库中可以为空,那么请务必使用DateTime?
作为关联的对象属性,否则EF将传入DateTime.MinValue
以获取超出范围的未分配值SQL日期时间类型可以处理的内容。
答案 7 :(得分:3)
初始化构造函数中的Start属性
Start = DateTime.Now;
当我尝试使用Code First向ASP .Net Identity Framework的用户表(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; }
}
答案 8 :(得分:1)
我有同样的问题,在我的情况下,我将日期设置为新的DateTime()而不是DateTime.Now
答案 9 :(得分:0)
在我的情况下,这发生在我使用实体时,sql表的默认值为datetime == getdate()。 所以我在这个领域设置了一个值。
答案 10 :(得分:0)
我正在使用Database First,当我发生此错误时,我的解决方案是在edmx文件中强制使用ProviderManifestToken =“2005”(使模型与SQL Server 2005兼容)。 不知道Code First是否有类似的东西。
答案 11 :(得分:0)
基于用户@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的评论
答案 12 :(得分:0)
一行可以解决此问题:
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部分。
答案 13 :(得分:0)
在我的情况下,在EF6中进行了一些重构后,我的测试失败了,并显示了与原始发布者相同的错误消息,但是我的解决方案与DateTime字段无关。
创建实体时,我只是缺少一个必填字段。一旦我添加了缺少的字段,错误就消失了。我的实体有两个DateTime吗?字段,但这不是问题。
答案 14 :(得分:-1)
如果有人像我一样讨厌,请仔细检查您约会的年份。我正在从YYMMDD格式的文本文件转换日期,因此创建的日期是0020年,而不是2020年。明显的错误,但是我花了更多时间在查看它,但没有看到我应有的时间!