Как исправить ошибку преобразования 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.Сейчас