Как исправить ошибку преобразования datetime2 вне диапазона с помощью DbContext и SetInitializer?
Я использую DbContext и Code First API, представленные в Entity Framework 4.1.
The модель данных использует базовые типы данных, такие как string и DateTime. Единственная аннотация данных, которую я использую в некоторых случаях, - это [Required], но это не на каких-либо DateTime свойства. Пример:
public virtual DateTime Start { get; set; }
The подкласс DbContext также просто и выглядит так:
public class EventsContext : DbContext
{
public DbSet<Event> Events { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Event>().ToTable("Events");
}
}
The инициализатор устанавливает даты в модель для разумных значений либо в этом году, либо в следующем году.
однако, когда я запускаю инициализатор, я получаю эту ошибку в context.SaveChanges():
преобразование данных datetime2 тип в тип данных datetime привело в значении вне диапазона. Этот заявление было прекращено.
Я не понимаю, почему это происходит вовсе не потому, что все так просто. Я также не уверен, как это исправить, так как нет файла edmx редактировать.
какие идеи?
11 ответов:
вы должны убедиться, что Start больше или равен SqlDateTime.MinValue (1 января 1753) - по умолчанию Start равен DateTime.MinValue (1 Января 0001).
простой. На свой код во-первых, установить тип datetime в тип datetime?. Так что вы можете работать с типом nullable 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; } }
В некоторых случаях
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();
вы можете сделать поле nullable, если это соответствует вашим конкретным задачам моделирования. Нулевая дата не будет принуждаться к дате, которая не находится в диапазоне типа SQL DateTime, как значение по умолчанию. Другой вариант-явно сопоставить с другим типом, возможно, с помощью,
.HasColumnType("datetime2")
хотя этот вопрос довольно старый и уже есть отличные ответы, я подумал, что должен поставить еще один, который объясняет 3 разных подхода к решению этой проблемы.
1-й подход
явного карте
DateTimeсвойстваpublic virtual DateTime Start { get; set; }доdatetime2в соответствующем столбце таблицы. Потому что по умолчанию EF будет сопоставлять его сdatetime.это может быть сделано с помощью fluent API или данных аннотация.
Fluent API
в классе DbContext overide
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; }2-й подход
инициализации
Startк значению по умолчанию в конструкторе EntityClass.Это хорошо, как будто по какой-то причине значениеStartне ставили перед сохранением сущности в базе данных всегда будет иметь значение по умолчанию. Убедитесь, что значение по умолчанию-больше или равно SqlDateTime.MinValue (с 1 января 1753 года по 31 декабря 9999 года)public class EntityClass { public EntityClass() { Start= DateTime.Now; } public DateTime Start{ get; set; } }3-й подход
сделать
Startиметь тип nullableDateTimeПримечание?послеDateTime-public virtual DateTime? Start { get; set; }для более подробного объяснения прочитайте это post
мое решение состояло в том, чтобы переключить все столбцы datetime на datetime2 и использовать datetime2 для любых новых столбцов. Другими словами, сделать EF использовать datetime2 по умолчанию. Добавьте это в метод OnModelCreating в вашем контексте:
modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));что получит все DateTime и DateTime? свойства для всех ваших объектов.
Если
DateTimeсвойства nullable в базе данных, то не забудьте использоватьDateTime?для связанных свойств объекта или EF будет проходить вDateTime.MinValueдля неназначенных значений, которые находятся вне диапазона того, что может обрабатывать тип SQL datetime.
инициализировать свойство Start в конструкторе
Start = DateTime.Now;это сработало для меня, когда я пытался добавить несколько новых полей в таблицу пользователей ASP .Net Identity Framework (AspNetUsers), используя сначала код. Я обновил класс-ApplicationUser в IdentityModels.cs и я добавили поле lastLogin типа DateTime.
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; } }
У меня была та же проблема, и в моем случае я устанавливал дату на новый DateTime() вместо DateTime.Сейчас