DbContext ve SetInitializer kullanarak datetime2 aralık dışı dönüştürme hatası nasıl düzeltilir?


136

Entity Framework 4.1 ile tanıtılan DbContext ve Code First API'lerini kullanıyorum.

Veri modeli gibi temel veri tiplerini kullanır stringve DateTime. Bazı durumlarda kullandığım tek veri açıklaması [Required], ancak bu DateTimeözelliklerin hiçbirinde değil . Misal:

public virtual DateTime Start { get; set; }

DBContext alt sınıf da benzeri basit ve görünüm geçerli:

public class EventsContext : DbContext
{
    public DbSet<Event> Events { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Event>().ToTable("Events");
    }
}

Başlatıcı bu yıl veya gelecek yıl ya mantıklı değerlere modelinde setleri tarihler.

Ancak başlatıcıyı çalıştırdığımda şu hatayı alıyorum context.SaveChanges():

Datetime2 veri türünün datetime veri türüne dönüştürülmesi, aralık dışı bir değerle sonuçlandı. Açıklama sona erdirildi.

Bunun neden olduğunu anlamıyorum çünkü her şey çok basit. Düzenlemek için edmx dosyası olmadığı için nasıl düzeltileceğinden de emin değilim.

Herhangi bir fikir?


2
SQL deyimlerini ekleme / güncelleme için SQL Profiler'ı kullanabilir misiniz? Burada neler olduğunu söylemek oldukça zor - başlatıcı veya varlıkları görmüyoruz. SQL Profiler sorunu yerelleştirmek için çok yardımcı olacaktır.
Ladislav Mrnka

1
Benim durumumda bir tablo ve düzenleme formuna bir alan ekledim, Bind Includes'i güncellemeyi unuttum ve alanım NULL olarak ayarlanmıştı. Bu yüzden hata gözetimimin düzeltilmesine yardımcı oldu.
strattonn

Yanıtlar:


186

Start öğesinin SqlDateTime.MinValue (1 Ocak 1753) değerinden büyük veya ona eşit olduğundan emin olmalısınız - varsayılan olarak Start öğesi DateTime.MinValue (1 Ocak 0001) değerine eşittir.


14
Başlangıç ​​nesnelerimin bazılarını ayarlanmış bir tarih olmadan bırakmıştım, bu yüzden DateTime.MinValue varsayılan olarak olurdu.
Alex Angas

Ben de yaptım ^. Asp.net kimliği ApplicationUser nesnesine özel bir tarih alanı eklendi, ardından mantıklı bir şeye başlatmayı unuttum. : (
Mike Devenney

Benim durumumda, sorun min. Tarihte, 01/01/0001 hatayı oluşturuyordu.
Machado

dateTime.minvalue'yu nasıl kontrol edebilirim?
Anabeil

1
Biraz geç, ama @Anabeil VS / linqpad
SIRHAMY

22

Basit. Önce kodunuzda DateTime türünü DateTime? Olarak ayarlayın. Böylece, veritabanında nulllable DateTime türüyle çalışabilirsiniz. Varlık örneği:

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; }
    }

6
bu her zaman böyle değildir. {1/1/0001 12:00:00} de bu hatayı ortaya
çıkarır

20

Bazı durumlarda, DateTime.MinValue(veya eşdeğer olarak default(DateTime)) bilinmeyen bir değeri belirtmek için kullanılır.

Bu basit genişletme yöntemi, bu tür durumların üstesinden gelmeye yardımcı olabilir:

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;
    }
}

Kullanımı:

 DateTime? dateToPassOnToDb = tooEarlyDate.ToNullIfTooEarlyForDb();

13

Belirli modelleme endişelerinize uygunsa alanı sıfırlanabilir yapabilirsiniz. Boş bir tarih, varsayılan bir değerin olacağı şekilde SQL DateTime türü aralığında olmayan bir tarihe zorlanmaz. Başka bir seçenek de, farklı bir türle,

.HasColumnType("datetime2")

12

Bu soru oldukça eski ve çoktan harika cevaplar olmasına rağmen, bu sorunu çözmek için 3 farklı yaklaşımı açıklayan bir tane daha koymam gerektiğini düşündüm.

1. Yaklaşım

Açıkça harita DateTimeözelliği public virtual DateTime Start { get; set; }için datetime2tablodaki sütun karşılık gelen içinde. Çünkü EF varsayılan olarak eşleyecektir datetime.

Bu, akıcı API veya veri notu ile yapılabilir.

  1. Akıcı API

    DbContext sınıfında OnModelCreatingözelliği geçersiz kıl ve yapılandır Start(açıklama nedenleriyle EntityClass sınıfının bir özelliğidir).

    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. Veri açıklaması

    [Column(TypeName="datetime2")]
    public virtual DateTime Start { get; set; }
    

2. Yaklaşım

StartEntityClass yapıcısında varsayılan bir değere başlat . Bu, herhangi bir nedenden dolayı Startvarlığı veritabanı başlangıcına kaydetmeden önce değerinin ayarlanmamış gibi olması iyi bir değerdir. Varsayılan değerin SqlDateTime.MinValue değerine eşit veya daha büyük olduğundan emin olun (1 Ocak 1753 - 31 Aralık 9999 arası)

public class EntityClass
{
    public EntityClass()
    {
        Start= DateTime.Now;
    }
    public DateTime Start{ get; set; }
}

3. Yaklaşım

Make Starttipi null olması DateTime -NOT ? sonra DateTime-

public virtual DateTime? Start { get; set; }

Daha fazla açıklama için bu okuma yazı


8

Senin Eğer DateTimeözellikler veritabanında null olan o kullandığınızdan emin olun DateTime?ilişkili nesne özellikleri için veya EF geçecek DateTime.MinValueSQL datetime tipi işleyebilir ne aralığın dışında atanmamış değerleri için.


8

Benim çözümüm, tüm datetime sütunlarını datetime2 olarak değiştirmek ve yeni sütunlar için datetime2 kullanmak oldu. Başka bir deyişle, EF'nin varsayılan olarak datetime2 kullanmasını sağlayın. Bağlamınızdaki OnModelCreating yöntemine ekleyin:

modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));

Bu tüm DateTime ve DateTime alacak? tüm varlıklarınızda.


3

yapıcıda Start özelliğini başlatma

Start = DateTime.Now;

Önce ASP kullanarak ASP .Net Identity Framework Kullanıcıları tablosuna (AspNetUsers) birkaç yeni alan eklemek çalışırken bu benim için çalıştı. Class - ApplicationUser'ı IdentityModels.cs içinde güncelledim ve DateTime türünde lastLogin alanı ekledim.

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; }
    }

2

User @ andygjp'nin cevabına göre, temel Db.SaveChanges()yöntemi geçersiz kılar ve SqlDateTime.MinValue ile SqlDateTime.MaxValue arasında olmayan herhangi bir tarihi geçersiz kılmak için bir işlev eklerseniz daha iyi olur .

İşte örnek kod

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 adlı kullanıcının https://stackoverflow.com/a/11297294/9158120 adresindeki yorumundan alınmıştır.


1

Aynı sorunu yaşadım ve benim durumumda DateTime yerine yeni DateTime () tarihi ayarlıyordum.


0

Benim durumumda bu varlık kullandığımda ve sql tablosu datetime == getdate () varsayılan değerine sahip olduğunda oldu. yani bu alana bir değer ayarlamak için ne yaptım.


0

Önce Veritabanı kullanıyorum ve bu hata bana olduğunda benim çözüm ProviderManifestToken = "2005" edmx dosyasında (modelleri SQL Server 2005 ile uyumlu hale getirmek) zorlamak oldu. Önce Kod için benzer bir şeyin mümkün olup olmadığını bilmiyorum.


0

Bir satır bunu düzeltir:

modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));

Yani, kodumda ekledim:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));
}

Bu satırı DBContext alt sınıfına geçersiz kılma geçersiz OnModelCreating bölümüne eklenmesi gerekir.


0

Benim durumumda, EF6'daki bazı yeniden düzenleme işlemlerinden sonra, testlerim orijinal posterle aynı hata iletisiyle başarısız oldu, ancak çözümümün DateTime alanlarıyla ilgisi yoktu.

Varlığı oluştururken gerekli bir alanı kaçırıyordum. Eksik alanı ekledikten sonra hata ortadan kalktı. İşletmemde iki DateTime var mı? sorun değillerdi.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.