Datetime2 veri türünün datetime veri türüne dönüştürülmesi aralık dışı değerle sonuçlanır


379

5 Satırlı bir datatable var, burada bir satır veri ile dolduruluyor ve sonra bir işlemle veritabanına kaydediliyor.

Kaydederken bir hata döndürülür:

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

Okunduğum gibi, datatable'ımın bir türüne DateTime2ve benim veritabanım a DateTime; bu yanlış.

Tarih sütunu şu şekilde ayarlanır DateTime:

new DataColumn("myDate", Type.GetType("System.DateTime"))

Soru

Bu kodla çözülebilir mi veya bir şey veritabanı düzeyinde değiştirilmeli mi?

Yanıtlar:


60

Sütunda ne tür tarihler var?

Hepsi tip aralığına uyuyor mu?


Bir kenara, kurucu Typeiçin bir nesne elde etmenin doğru yolu , daha hızlı büyüklük sırası olan anahtar kelimedir.DataColumntypeof

Bu nedenle, sütun oluşturmak için şunu yazmalısınız:

new DataColumn("myDate", typeof(DateTime))

3
Veri sütunlarımı değiştirdim ve şimdi typeof kullandım ... Dahası sorunumu buldum. hatayı tetikleyen yanlış bir tarih içeren 1 datarow vardı
Gerbrand

739

Alan NULL değerleri kabul etmediğinde bir DateTime alanına değer atamazsanız bu durum oluşabilir .

Bu benim için sorunumu çözdü!


43
Entity Framework'te, null olmayan bir Oluşturulmuş sütun eklerseniz EDMX'inizi güncelleyin, koddaki değeri ayarlamadığınızda bu hatayı bu şekilde atabilir
Brad Thomas

6
Senin için ne düzeltti? Varsayılan değer olarak getdate () çağrısına sahip bir datetime alanınız olduğunda bu hata görünür.
user3046061

15
Neden SQL tarafında, varsayılan bir değer = getdate () var çünkü NULL varsa Entity Framework göz ardı edemiyor?
JoshYates1980

33
Ne olduğuna inanıyorum EntityFramework 0001 yıl ve SQL datetime aralık değeri dışında bir DateTime.MinValue görür, bu nedenle bu değeri bir DateTime2 (yıl 0001 destekleyen) değeri olarak gönderir, böylece ekleme / güncelleştirme geçerli, ancak SQL bu DateTime2'yi DateTime'a dönüştürmeye çalıştığında başarısız olur, çünkü bu farklı bir değere neden olur. İki çözüm şunlardır: 1 Modelinizde nullable datetime kullanın veya 2. bağlam tarihlerini kaydetmeden önce tüm datetime değerlerinizi doğru değere başlatın. Yaptığınız seçim, modelinizde tarih saatinin ne anlama geldiğine bağlıdır.
Guillermo Ruffino

1
@ GuillermoRuffino'nun çözümü benim için çalıştı. Tüm alanlarınızı inceleyin ve bu 0001 yıllık girişleri bulun.
Francesco

158

Hem DATETIMEve DATETIME2eşleme System.DateTime.NET içinde - gerçekten aynı .NET türü olduğundan gerçekten bir "dönüşüm" yapamaz.

MSDN doc sayfasına bakın: http://msdn.microsoft.com/en-us/library/bb675168.aspx

SqlDbTypeBu ikisi için " " için iki farklı değer vardır - DataColumntanımınızdakileri belirtebilir misiniz ?

AMA: SQL Server'da desteklenen tarih aralığı oldukça farklı.

DATETIME1753/1/1 ila "sonsuzluk" u (9999/12/31) DATETIME2desteklerken, sonsuzluk boyunca 0001/1/1 değerini destekler.

Gerçekten yapmanız gereken tarih yılını kontrol etmektir - 1753'ten önce ise DATETIME, SQL Server'daki sütunun işlemesi için 1753 SONRASI bir şeyle değiştirmeniz gerekir.

üzüm posası


7
Bu benim yaşadığım problemi açıklıyor. 1753/1/1 öncesi gerçek tarihlerin ele alınması gereken birkaç durum olsa da, hataya neden olabilecek 0001/1/1 varsayılan değerini alan birçok durum vardır.
Hong

Bir 'datetime' veri türüne 'yeni bir DateTime ()' eklemek çalışırken bu özel durum aldığımı onaylıyorum.
George Onofrei

1
Bir veritabanına yazdı benim C # kodunda DateTime.MinValue varsayılan bir değer atamaya çalışıyordu. Bu, aldığım hatayı açıklıyor. +1
Mkalafut

Kullandığım Varlık Framework Kod İlk ve ben DateTime özelliğiyle modelini kullanır. DtInit = new System.DateTime(1492, 10, 12),başarısız olur.
Kiquenet

Bu, gerçek nedenin yamanın arkasında saklandığı durumlardan biridir ... +1
Eugenio Miró

41

SQL Server 2008 veritabanımda, DateTimenull GetDate()değeri olmayan, ancak varsayılan değeri olarak bir işlevi olan bir sütun vardı . EF4 kullanarak yeni nesne eklerken, nesneme açıkça bir DateTime özelliği geçirmediğim için bu hatayı aldım. SQL işlevinin benim için tarihi işlemesini bekliyordum ama olmadı. Benim çözüm üretmek için veritabanına güvenmek yerine koddan tarih değerini göndermek oldu.

obj.DateProperty = DateTime.now; // C#

2
Yardımcı olduğuma sevindim. Bu sinir bozucu çünkü EF veri içeriğinin, nesne tablodan oluşturulduğunda alanın varsayılan bir değere sahip olduğunu keşfedebileceğini düşünürdünüz.
Graham

EF hakkında birçok şey düşünürdüm. POCO kendi kendine izleme varlıkları kullanıyorum ve böyle bir küme. Ben kod ilk modeli kontrol edeceğim, ve bu da saçmalık dolu ise ciddi ciddi sql linq geri dönüp kendi nesneleri için sahne eşleştirmek için bir nesne eşleyici kullanarak düşünüyorum ...

2
2 hafta önce VS Live'da EF Code'un ilk demosunu gördüm ve AWESOME, btw'ye baktı.
Graham

Bu iyi haber. Yakında ofisimde yeni bir proje başlatıyoruz ve EF-CF ve dapper'a (SO tarafından kullanılıyor / sürdürülüyor) ayrıldım . Bir WCF servisi aracılığıyla kullanılan bir uygulamada muhtemelen daha iyi olacak.

1
Merhaba, eski yorumlar! Kendim EF Code-First ile başlıyorum ve benim POCO üzerinde sadece datetime üyemi tanımlamak gerektiğini Nullable<DateTime>ve kodda ben bu gerçekten boş (01/01/0000 yerine) bırakabilirsiniz bulundu. SQL'den EF'in bu boş değeri INSERT'te görmezden geldiğini ve sunucudaki tarihi kullandığını ( GetDate()) gösterdiğini görmek hoş bir sürpriz oldu. web sunucusu ve sql sunucusunun sunucusudur.
Funka

34

benim için tarih olduğu için ..

01/01/0001 00:00:00

bu durumda EF DateTime Object'e null atamak istiyorsunuz ... FirstYearRegistered kodumu örnek olarak kullanarak

DateTime FirstYearRegistered = Convert.ToDateTime(Collection["FirstYearRegistered"]);
if (FirstYearRegistered != DateTime.MinValue)
{
    vehicleData.DateFirstReg = FirstYearRegistered;
}  

Bu verileri ExcelDataReader kullanarak ayrıştırıyorum ve geçersiz metin girildiğinde (.GetDateTime (columnIndex) yöntemini kullanarak beklendiği gibi bir istisna atmaz) 01/01/0001 döndürüyor. MinValue ile karşılaştırma, sql'deki aralık dışı istisnayı önlemek için hile yaptı.
Tommy

22

Bu beni delirtiyordu. Geçersiz bir tarih ( DateTime?) kullanmaktan kaçınmak istedim . SQL Server 2008'in datetime2türünü kullanma seçeneğim de yoktu

modelBuilder.Entity<MyEntity>().Property(e => e.MyDateColumn).HasColumnType("datetime2");

Sonunda aşağıdakileri seçtim:

public class MyDb : DbContext
{
    public override int SaveChanges()
    {
        UpdateDates();
        return base.SaveChanges();
    }

    private void UpdateDates()
    {
        foreach (var change in ChangeTracker.Entries<MyEntityBaseClass>())
        {
            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;
                    }
                }
            }
        }
    }
}

1
Kullanarak [Column(TypeName = "datetime2")]?
Kiquenet

21

Bazen EF bunun hesaplanmış bir sütun veya bir tetikleyici ile uğraştığını bilmez . Tasarım gereği, bu işlemler bir kesici uçtan sonra EF dışında bir değer ayarlayacaktır.

Düzeltme özelliği , özelliği sütun için ComputedEF'lerde belirtmektir .edmxStoreGeneratedPattern

Benim için, sütunun geçerli tarih ve saati ekleyen bir tetikleyicisi olduğunda, üçüncü bölüme bakın.


Çözümleme Adımları

Visual Studio'da Model Browsersayfayı açın ve Modelsonra Entity Types-> sonra

  1. Varlığı ve tarih ve saat özelliğini seçin
  2. seçmek StoreGeneratedPattern
  3. Ayarlanır Computed

EF Model Tarayıcı Modeli Varlık Türü iletişim kutusu


Bu durumda, diğer yanıtlar geçici çözümlerdir, sütunun amacı kayıt oluşturulduğunda belirtilen bir saat / tarih belirtmektir ve doğru zamanı eklemek için bir tetikleyici çalıştırmak SQL'in görevidir. Bu SQL tetikleyicisi gibi:

DEFAULT (GETDATE()) FOR [DateCreated].


O sırada GETDATE()tam anlamıyla kullandığımı kullandığımı unutmayın . Ancak yakın zamanda, SYSDATETIME()doğru olduğuna inandığım herhangi bir DateTime2 işlemi için kullanılması gereken bir yorum vardı .
MmegaMan

10

Ben bu koştu ve datetime özelliği aşağıdaki ekledi:

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

1
using System.ComponentModel.DataAnnotations.Schema; gereklidir
Kiquenet

9

Bir tarih-zaman-saat alanı geçmezsek, varsayılan tarih {1/1/0001 12:00:00 AM} geçer.

Ancak bu tarih varlık çerçevesi çalışmasıyla uyumlu değil, bu nedenle datetime2 veri türünün datetime veri türüne dönüştürülmesini aralık dışı bir değerle sonuçlandıracak

Sadece default DateTime.nowtarihi alanına Eğer herhangi bir tarih geçen değilse.

movie.DateAdded = System.DateTime.Now

'DateTime.Now' varsayılan bir değer olarak geçen söyleyebilirim doğru olmaktan çok uzak ve oldukça yanıltıcı.
Bartosz

6

En kolay şey, veritabanınızı datetime yerine datetime2 kullanacak şekilde değiştirmek olacaktır. Uyumluluk iyi çalışır ve hatalarınızı alamazsınız.

Yine de bir sürü test yapmak isteyeceksiniz ...

Hata muhtemelen 0 yılına bir tarih ayarlamaya çalışmanızdır, ancak her şey bir şeyi değiştirmek için kontrolünüzün nerede olduğuna bağlıdır.


4

Bu yazıyı neden diğer cevaplarla açıklanmış aşağıdaki hatayı almaya devam ettiğimi anlamaya çalışırken buldum.

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

Boş bir DateTime nesnesi kullanın.
herkese açık DateTime? PurchaseDate {get; Ayarlamak; }

Varlık çerçevesi kullanıyorsanız edmx dosyasındaki nullable özelliğini True olarak ayarlayın

Edmx dosyasındaki nulllable özelliğini ** True ** olarak ayarlayın


3

Andyuk'un daha önce işaret ettiği gibi , bu, boş olmayan bir DateTime alanına bir NULL değeri atandığında gerçekleşebilir . DateTime'ı DateTime olarak değiştirmeyi düşünüyor musunuz? veya Nullable < DateTime >. Bir Bağımlılık Özelliği kullanıyorsanız , bağımlılık özelliğinizin türünün de boş değerli bir DateTime türü olduğundan emin olmanız gerektiğini unutmayın.

Aşağıda eksik bir DateTime to DateTime gerçek hayat örneği var mı? garip davranışı arttıran tip ayarı

resim açıklamasını buraya girin


2

Entity Framework 4 datetime2 veri türüyle çalışır, böylece db'de karşılık gelen alanın SQL Server 2008 için datetime2 olması gerekir.

Çözümü elde etmek için iki yol vardır.

  1. Entity Framwork 4'te datetime veri türünü kullanmak için edmx dosyasındaki ProviderManifestToken öğesini "2005" olarak değiştirmeniz gerekir.
  2. İlgili alanı Null'a İzin Ver olarak ayarlarsanız (alan NULLABLE'a dönüştürür), böylece EF otomatik olarak tarih nesnelerini datetime olarak kullanır.

1
Veritabanı modellerim için ikinci noktanızı aldım (POCO sınıfları) ve bir alanı nullable tip olarak nasıl ayarlayacağımı merak ettim. Herhangi birinin merak etmesi durumunda, tarih türünden sonra bir Soru İşareti (?) Ekleyerek bunu yapabilirsiniz. örneğin, kamuya açık DateTime? StartTime {get; Ayarlamak; } Bu benim için sorunu çözdü. Yapmam gereken tek şey, birbirinden iki nulllable DateTime değeri çıkardığım bir kod satırı etrafına bir TimeSpan dökümü yapmaktı. örneğin var timeTaken = (TimeSpan) (endTime - startTime);
Ciaran Gallagher

1

@ Sky-dev uygulamasına dayalı bir temel sınıf oluşturuldu. Böylece bu, birden çok bağlam ve varlığa kolayca uygulanabilir.

public abstract class BaseDbContext<TEntity> : DbContext where TEntity : class
{
    public BaseDbContext(string connectionString)
        : base(connectionString)
    {
    }
    public override int SaveChanges()
    {

        UpdateDates();
        return base.SaveChanges();
    }

    private void UpdateDates()
    {
        foreach (var change in ChangeTracker.Entries<TEntity>())
        {
            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;
                    }
                }
            }
        }
    }
}

Kullanımı:

public class MyContext: BaseDbContext<MyEntities>
{

    /// <summary>
    /// Initializes a new instance of the <see cref="MyContext"/> class.
    /// </summary>
    public MyContext()
        : base("name=MyConnectionString")
    {
    }
    /// <summary>
    /// Initializes a new instance of the <see cref="MyContext"/> class.
    /// </summary>
    /// <param name="connectionString">The connection string.</param>
    public MyContext(string connectionString)
        : base(connectionString)
    {
    }

     //DBcontext class body here (methods, overrides, etc.)
 }

1

Model sınıfınızdaki özelliğe aşağıda belirtilen özelliği ekleyin.

Attribute = [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
Reference = System.ComponentModel.DataAnnotations.Schema

Başlangıçta bu özelliği eklemeyi unuttum. Veritabanımda kısıtlama şu şekilde oluşturuldu:

ALTER TABLE [dbo].[TableName] ADD DEFAULT (getdate()) FOR [ColumnName]

ve bu özniteliği ekledim ve db'imi güncelledim ve daha sonra

ALTER TABLE [dbo].[TableName] ADD CONSTRAINT [DF_dbo.TableName_ColumnName] DEFAULT (getdate()) FOR [ColumnName]

[DatabaseGenerated (DatabaseGeneratedOption.Computed)]
Ajith Chandran


0

Bazen sunucularda değil, geliştirme makinelerinde iyi çalışır. Benim durumumda:

<globalization uiCulture="es" culture="es-CO" />

Web.config dosyasında.

Makinede (Sunucu) saat dilimi haklıydı (CO yerel ayarına) ama web uygulaması yapmadı. Bu ayar yapıldı ve yine iyi çalıştı.

Elbette, tüm tarihlerin değeri vardı.

: D


0

ASP.NET'te bir sınıfa bu kodu eklemek benim için çalıştı:

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

0

Bu sorunun farkındayım ve hepiniz de öyle olmalısınız:

https://en.wikipedia.org/wiki/Year_2038_problem

SQL'de bu sorunu önlemek için yeni bir alan türü oluşturuldu (datetime2).

Bu 'Tarih' alan türü, DateTime .Net sınıfıyla aynı aralık değerlerine sahiptir. Tüm sorunlarınızı çözecektir, bu yüzden çözmenin en iyi yolunun veritabanı sütun türünüzü değiştirdiğini düşünüyorum (tablo verilerinizi etkilemez).


0

Aşağıdaki ikiye göz atın: 1) Bu alanın NULL değeri yoktur. Örneğin:

 public DateTime MyDate { get; set; }

Şununla değiştir:

public DateTime MyDate { get; set; }=DateTime.Now;

2) Yeni veritabanı tekrar. Örneğin:

db=new MyDb();

Değer varsayılan olarak DateTime.Now olmasını istemezseniz ne olur?
Savage

Bunu yapmak istemiyorsanız: DateTime.Now. Kullanabilirsiniz: yeni DateTime (..., ..., ...)
RainyTears

0

Devralınan datetime özniteliğiyle ilgili sorun

Bu hata iletisi genellikle, geçersiz olmayan bir tarih alanı ekleme / güncelleme zamanında null değerine sahip olduğunda gösterilir. Bir sebep kalıtım olabilir.

Tarihiniz bir temel sınıftan devralındıysa ve eşleme yapmıyorsanız EF bu değeri okumaz.

Daha fazla bilgi için: https://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-3-table-per-concrete-type-tpc-and- -strateji-yönergelere seçme


0

ASP.Net MVC usnig sayfasını düzenlemek istediğimde bu hatayı gördüm. Oluşturma sırasında hiçbir sorunum olmadı, ancak Veritabanını Güncelleme DateCreated özelliğini kapsama alanı dışında bıraktı!

Eğer istemiyorsanız DateTimeMülkiyet null olması ve yapılacak değeri sql DateTime aralığında olup olmadığını kontrol etmek istemiyor (ve @Html.HiddenForyardım değil!), Basit bir ekleme static DateTimeilgili sınıf (Kontrolör) iç alanını ve bu zaman değer vermek GET çalışıyor ve POST işini yaparken kullan:

public class PagesController : Controller
{
    static DateTime dateTimeField;
    UnitOfWork db = new UnitOfWork();

    // GET:
    public ActionResult Edit(int? id)
    {
        Page page = db.pageRepository.GetById(id);
        dateTimeField = page.DateCreated;
        return View(page);
    }

    // POST: 
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(Page page)
    {
        page.DateCreated = dateTimeField;
        db.pageRepository.Update(page);
        db.Save();
        return RedirectToAction("Index");

    }
}

0

Basit bir konsol uygulaması projesinde bu sorunla karşılaştım ve hızlı çözümüm, bu yöntemi çalıştırarak olası datetime2 tarihlerini boş değerli bir tarih saatine dönüştürmektir:

static DateTime? ParseDateTime2(DateTime? date)
    {
        if (date == null || date.ToString() == "1/1/0001 12:00:00 AM")
        {
            return null;
        }
        else
        {
            return date;
        }
    }

Bu kesinlikle tamamen kapsamlı bir yöntem değil, ama ihtiyaçlarım için çalıştı ve belki başkalarına yardımcı olacaktır!


0

DB'de gerekli formatı kontrol edin. ör. DB'mde Varsayılan değer veya Bağlama var(((1)/(1))/(1900))

System.DateTime MyDate = new System.DateTime( 1900 ,1, 1);

resim açıklamasını buraya girin


-1

1/1/1001 gibi izin verilen dattime min değerini lesathan olarak ayarlanmış tarih sütununa sahip olacaksınız.

Bu sorunun üstesinden gelmek için ur özelliğine uygun datetime değerini ayarlayabilirsiniz.

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.