Как исправить ошибку преобразования datetime2 вне диапазона с помощью DbContext и SetInitializer?

Я использую DbContext и первые API кода, введенные с Entity Framework 4.1.

на модель данных использует базовые типы данных, такие как 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 тип к типу данных datetime в значении вне диапазона. Этот заявление было прекращено.

Я не понимаю, почему это происходит вовсе не потому, что все так просто. Я также не уверен, как это исправить, так как нет файла edmx для редактировать.

какие идеи?

11 ответов


вы должны убедиться, что Start больше или равен SqlDateTime.MinValue (1 января 1753) - по умолчанию Start равен DateTime.MinValue (1 Января 0001).


простой. В вашем коде сначала установите тип DateTime в DateTime?. Таким образом, вы можете работать с типом DateTime nullable в базе данных. Пример сущности:

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 (или equivalenly, 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; } to datetime2 в соответствующем столбце таблицы. Потому что по умолчанию EF сопоставит его с datetime.

это можно сделать с помощью fluent API или данных аннотация.

  1. свободно 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"));
    }
    
  2. аннотации

    [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 быть типа nullable DateTime Примечание ? после DateTime-

public virtual DateTime? Start { get; set; }

более подробное объяснение читайте этот в должности


моим решением было переключить все столбцы 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; }
    }

У меня была та же проблема, и в моем случае я устанавливал дату на new DateTime() вместо DateTime.Теперь


в моем случае это произошло, когда я использовал entity, а таблица sql имеет значение по умолчанию datetime == getdate(). Итак, что я сделал, чтобы установить значение для этого поля.


сначала я использую базу данных, и когда эта ошибка произошла со мной, моим решением было заставить ProviderManifestToken="2005" в файле edmx (что делает модели совместимыми с SQL Server 2005). Не знаю, возможно ли что-то подобное для кода First.