Konwersja typu danych datetime2 na typ danych datetime powoduje, że wartość jest poza zakresem

379

Mam dane z 5 kolumnami, w których wiersz jest wypełniany danymi, a następnie zapisywany w bazie danych za pośrednictwem transakcji.

Podczas zapisywania zwracany jest błąd:

Konwersja typu danych datetime2 na typ danych datetime spowodowała przekroczenie zakresu

Oznacza to, jak czytano, że mój plik DateTime2danych ma typ, a moja baza danych a DateTime; to jest złe.

Kolumna daty ma następującą wartość DateTime:

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

Pytanie

Czy można to rozwiązać za pomocą kodu lub czy trzeba coś zmienić na poziomie bazy danych?

Gerbrand
źródło

Odpowiedzi:

60

Jakie masz daty w kolumnie?

Czy wszystkie z nich mieszczą się w zakresie tego typu?


Nawiasem mówiąc, poprawnym sposobem uzyskania Typeobiektu dla DataColumnkonstruktora jest typeofsłowo kluczowe, które jest o rząd wielkości szybsze.

Dlatego, aby utworzyć kolumnę, powinieneś napisać

new DataColumn("myDate", typeof(DateTime))
SLaks
źródło
3
Zmieniłem teraz moje kolumny danych i użyłem typeof ... Dalej znalazłem swój problem. była 1 datarow, która zawierała niewłaściwą datę, co spowodowało błąd
Gerbrand
739

Może się to zdarzyć, jeśli nie przypiszesz wartości do pola DateTime, gdy pole nie przyjmuje wartości NULL .

To naprawiło to dla mnie!

andyuk
źródło
43
Jeśli w Entity Framework dodasz kolumnę Utworzony, która nie ma wartości NULL, a następnie zaktualizujesz EDMX, gdy nie ustawiasz wartości w kodzie, może to spowodować zgłoszenie tego błędu w ten sposób
Brad Thomas
6
Co to dla ciebie naprawiło? Ten błąd pojawia się, gdy masz pole daty i godziny z wywołaniem getdate () jako wartością domyślną.
user3046061
15
Dlaczego środowisko Entity Framework nie może ignorować wartości NULL, ponieważ po mojej stronie SQL mam wartość domyślną = getdate ()?
JoshYates1980,
33
Wydaje mi się, że tak się dzieje, że EntityFramework widzi DateTime.MinValue, który jest rokiem 0001, a w SQL datetime jest poza wartością zakresu, więc wysyła tę wartość jako wartość DateTime2 (która obsługuje rok 0001), więc wstawianie / aktualizacja jest poprawna, jednak kończy się niepowodzeniem, gdy SQL próbuje przekonwertować DateTime2 na DateTime, ponieważ spowoduje to inną wartość. Dwa rozwiązania to: 1 Użyj zerowego datetime w swoim modelu lub 2. zainicjuj wszystkie wartości datetime, aby uzyskać prawidłową wartość przed zapisaniem zmian kontekstu. Dokonany wybór zależy od tego, co oznacza data i godzina w modelu.
Guillermo Ruffino
1
@ Rozwiązanie GuillermoRuffino zadziałało dla mnie. Sprawdź wszystkie swoje pola i znajdź wpisy 0001 lat.
Francesco B.
158

Zarówno DATETIMEi DATETIME2odwzorowanie na System.DateTime.NET - tak naprawdę nie można wykonać „konwersji”, ponieważ jest to naprawdę ten sam typ .NET.

Zobacz stronę dokumentu MSDN: http://msdn.microsoft.com/en-us/library/bb675168.aspx

Istnieją dwie różne wartości „ SqlDbType” dla tych dwóch - czy możesz podać te w swojej DataColumndefinicji?

ALE: w SQL Server obsługiwany zakres dat jest zupełnie inny.

DATETIMEobsługuje 1753/1/1 do „wieczności” (9999/12/31), a jednocześnie DATETIME2wspiera 0001/1/1 przez wieczność.

Tak więc, co naprawdę musisz zrobić, to sprawdzić rok daty - jeśli jest on wcześniejszy niż 1753, musisz zmienić go na coś PO 1753, aby DATETIMEkolumna w SQL Server mogła to obsłużyć.

Marc

marc_s
źródło
7
To wyjaśnia problem, który miałem. Chociaż jest kilka sytuacji, w których należy traktować rzeczywiste daty sprzed 1753/1/1, ale jest wiele sytuacji, w których otrzymuje się wartość domyślną 0001/1/1, która może powodować błąd.
Hong
Potwierdzam, że kiedy próbowałem wstawić „new DateTime ()” do typu danych „datetime”, otrzymałem ten wyjątek.
George Onofrei
1
Próbowałem przypisać domyślną wartość DateTime.MinValue w moim kodzie C #, który zapisał do bazy danych. To wyjaśnia występujący błąd. +1
Mkalafut,
Najpierw używam Entity Framework Code i używam modelu z właściwością DateTime. DtInit = new System.DateTime(1492, 10, 12),zawodzi.
Kiquenet,
Jest to jedna z tych sytuacji, w których prawdziwy powód jest ukryty za łatką ... +1
Eugenio Miró
41

W mojej bazie danych SQL Server 2008 miałem DateTimeflagę oznaczoną jako nie zerowalna, ale z GetDate()funkcją jako wartością domyślną. Podczas wstawiania nowego obiektu za pomocą EF4 wystąpił ten błąd, ponieważ nie przekazałem jawnie właściwości DateTime na mój obiekt. Spodziewałem się, że funkcja SQL obsłuży dla mnie datę, ale tak nie było. Moim rozwiązaniem było wysłanie wartości daty z kodu zamiast polegać na bazie danych w celu jej wygenerowania.

obj.DateProperty = DateTime.now; // C#
Graham
źródło
2
Miło, że mogłem pomóc. Jest to denerwujące, ponieważ można by pomyśleć, że kontekst danych EF mógłby odkryć, że pole ma wartość domyślną, gdy obiekt jest tworzony z tabeli.
Graham,
Myślałbym wiele rzeczy o EF. Używam jednostek śledzenia POCO i jest to taki klaster. Idę sprawdzić kod pierwszego modelu, a jeśli to również jest pełen bzdur jestem poważnie myśli o powrocie do LINQ to SQL i za pomocą mapowania obiektów do mapy rekwizyty do moich własnych jednostek ...
2
Widziałem demo EF Code First na VS Live 2 tygodnie temu i wyglądało to NIESAMOWITE, btw.
Graham
To dobra wiadomość. Wkrótce rozpoczynamy nowy projekt w moim biurze, a ja jestem podzielony na EF-CF i elegancki (używany / obsługiwany przez SO). Prawdopodobnie sprowadzi się do tego, co jest lepsze w aplikacji używanej za pośrednictwem usługi WCF.
1
Cześć, roczne komentarze! Ja sam zaczynam od EF Code-First i stwierdziłem, że na moim POCO muszę tylko zdefiniować mojego członka datetime jako Nullable<DateTime>, aw kodzie mogę pozostawić to naprawdę puste (zamiast 01/01/0000). Byłem mile zaskoczony, widząc, że EF na SQL wiedział, że ignoruje wartość null na INSERT i używa daty z serwera ( GetDate()) ... Dla nas było to nawet lepsze, ponieważ potrzebowaliśmy lepszej spójności na serwerze, nie martwiąc się o różnice zegarowe między serwer WWW i serwer SQL.
Funka
34

dla mnie to dlatego, że data i godzina były ...

01/01/0001 00:00:00

w tym przypadku chcesz przypisać null do obiektu EF DateTime ... używając mojego kodu FirstYearRegistered jako przykładu

DateTime FirstYearRegistered = Convert.ToDateTime(Collection["FirstYearRegistered"]);
if (FirstYearRegistered != DateTime.MinValue)
{
    vehicleData.DateFirstReg = FirstYearRegistered;
}  
JGilmartin
źródło
Analizuję te dane za pomocą ExcelDataReader i zwraca 01/01/0001, gdy wprowadzono niepoprawny tekst (nie zgłasza wyjątku zgodnie z oczekiwaniami - przy użyciu metody .GetDateTime (columnIndex)). Porównanie z MinValue pomogło zapobiec wyjątkowi spoza zakresu w sql.
Tommy
22

Ten doprowadzał mnie do szału. Chciałem uniknąć używania zerowej wartości daty i godziny ( DateTime?). Nie miałem możliwość korzystania z SQL Server 2008 za datetime2typ albo

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

W końcu zdecydowałem się na następujące:

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;
                    }
                }
            }
        }
    }
}
sky-dev
źródło
1
Używasz [Column(TypeName = "datetime2")]?
Kiquenet,
21

Czasami EF nie wie, że ma do czynienia z kolumną obliczeniową lub wyzwalaczem . Z założenia operacje te ustawią wartość poza EF po wstawieniu.

Poprawka polega na określeniu Computedw EF edmxdla tej kolumny we StoreGeneratedPatternwłaściwości.

Dla mnie to było, gdy kolumna miała wyzwalacz, który wstawił bieżącą datę i godzinę, patrz poniżej w trzeciej części.


Kroki, aby rozwiązać

W Visual Studio otwórz Model Browserstronę, a Modelnastępnie Entity Types-> następnie

  1. Wybierz encję i właściwość daty i godziny
  2. Wybierz StoreGeneratedPattern
  3. Ustawić Computed

Okno dialogowe Typ modelu przeglądarki EF Model jednostki


W tej sytuacji innymi odpowiedziami są obejścia, ponieważ kolumna ma określić czas / datę, kiedy rekord został utworzony, a zadaniem SQL jest wykonanie wyzwalacza w celu dodania poprawnego czasu. Takich jak ten wyzwalacz SQL:

DEFAULT (GETDATE()) FOR [DateCreated].

ΩmegaMan
źródło
Zauważ, że użyłem tego, GETDATE()co dosłownie wtedy zrobiłem. Ale ostatnio pojawił się komentarz, którego należy używać SYSDATETIME()do wszelkich operacji DateTime2, które uważam za prawdziwe.
ΩmegaMan
10

Natknąłem się na to i dodałem następujące elementy do mojej właściwości datetime:

 [Column(TypeName = "datetime2")]
 public DateTime? NullableDateTimePropUtc { get; set; }
Rogala
źródło
1
using System.ComponentModel.DataAnnotations.Schema; jest wymagane
Kiquenet,
9

Jeśli nie przekażemy pola data-godzina-data, domyślna data {1/1/0001 12:00:00 AM} zostanie zatwierdzona.

Ale ta data nie jest zgodna z pracą ramki encji, więc spowoduje rzutowanie konwersji typu danych datetime2 na typ danych datetime, co spowoduje powstanie wartości spoza zakresu

Tylko default DateTime.nowdo pola daty, jeśli nie przekazujesz żadnej daty.

movie.DateAdded = System.DateTime.Now
Lijo
źródło
Powiedziałbym, że podanie „DateTime.Now” jako wartości domyślnej jest dalekie od poprawności i raczej wprowadza w błąd.
Bartosz
6

Najłatwiej byłoby zmienić bazę danych, aby używała datetime2 zamiast datetime. Kompatybilność działa dobrze i nie dostaniesz błędów.

Nadal będziesz chciał przeprowadzić wiele testów ...

Błąd prawdopodobnie wynika z tego, że próbujesz ustawić datę na rok 0 lub coś takiego - ale wszystko zależy od tego, gdzie masz kontrolę nad zmianą.

Rob Farley
źródło
4

Znalazłem ten post, próbując dowiedzieć się, dlaczego wciąż pojawia się następujący błąd, który jest wyjaśniony przez inne odpowiedzi.

Konwersja typu danych datetime2 na typ danych datetime spowodowała przekroczenie zakresu.

Użyj zerowalnego obiektu DateTime.
Data publiczna? Data zakupu {get; zestaw; }

Jeśli używasz struktury encji Ustaw właściwość zerowalną w pliku edmx na True

Ustaw właściwość zerowalną w pliku edmx na ** True **

smród
źródło
3

Jak już zauważył andyuk , może się to zdarzyć, gdy wartość NULL zostanie przypisana do niezerowalnego pola DateTime . Rozważyć zmianę DateTime na DateTime? lub Nullable < DateTime >. Należy pamiętać, że w przypadku korzystania z właściwości zależności należy również upewnić się, że typ właściwości zależności jest również dopuszczalnym typem wartości DateTime.

Poniżej znajduje się prawdziwy przykład niepełnego DateTime to DateTime? dostosowanie typu, które podnosi dziwne zachowanie

wprowadź opis zdjęcia tutaj

Julio Nobre
źródło
2

Entity Framework 4 działa z typem danych datetime2, więc w db odpowiednim polem musi być datetime2 dla SQL Server 2008.

Aby uzyskać rozwiązanie, istnieją dwa sposoby.

  1. Aby użyć typu danych datetime w Entity Framwork 4, musisz przełączyć ProviderManifestToken w pliku edmx na „2005”.
  2. Jeśli ustawisz odpowiednie pole jako Zezwalaj na Null (konwertuje je na NULLABLE), wówczas EF automatycznie użyje obiektów daty jako daty i godziny.
Mahmut C.
źródło
1
Podniosłem twój drugi punkt dla moich modeli baz danych (klasy POCO) i zastanawiałem się, jak ustawić pole jako typ zerowalny. Jeśli ktoś się zastanawiał, możesz to zrobić, dodając znak zapytania (?) Po typie daty. np. publiczna data i godzina? StartTime {get; zestaw; } To rozwiązało problem. Jedyne, co musiałem zrobić, to umieścić rzutowanie TimeSpan wokół wiersza kodu, w którym odejmowałem od siebie dwie dopuszczające się wartości DateTime. np. var timeTaken = (TimeSpan) (endTime - startTime);
Ciaran Gallagher
1

Utworzono klasę bazową na podstawie implementacji @ sky-dev. Można to łatwo zastosować do wielu kontekstów i podmiotów.

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

Stosowanie:

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.)
 }
dynamiclynk
źródło
1

Dodaj niżej wymieniony atrybut do właściwości w swojej klasie modelu.

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

Początkowo zapomniałem dodać ten atrybut. Tak więc w mojej bazie danych zostało utworzone ograniczenie

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

i dodałem ten atrybut i zaktualizowałem moją bazę danych, a następnie zmieniłem ją na

ALTER TABLE [dbo].[TableName] ADD CONSTRAINT [DF_dbo.TableName_ColumnName] DEFAULT (getdate()) FOR [ColumnName]
Ajith Chandran
źródło
[DatabaseGenerated (DatabaseGeneratedOption.Computed)]
Ajith Chandran
0

Czasami działa dobrze na komputerach programistycznych, a nie na serwerach. W moim przypadku musiałem podać:

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

W pliku web.config.

Strefa czasowa na komputerze (serwerze) była odpowiednia (do ustawień regionalnych CO), ale aplikacja internetowa nie. To ustawienie zostało wykonane i znowu działało poprawnie.

Oczywiście wszystkie daty miały wartość.

:RE

Jaime Enrique Espinosa Reyes
źródło
0

Dodanie tego kodu do klasy w ASP.NET działało dla mnie:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));
}
Howie Krauth
źródło
0

Mam świadomość tego problemu i wszyscy też powinniście być:

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

W SQL utworzono nowy typ pola, aby uniknąć tego problemu (datetime2).

Ten typ pola „Data” ma te same wartości zakresu, co klasa .Net DateTime. Rozwiąże wszystkie twoje problemy, więc myślę, że najlepszym sposobem na jego rozwiązanie jest zmiana typu kolumny bazy danych (nie wpłynie to na dane w tabeli).

marcolomew
źródło
0

Sprawdź następujące dwa: 1) To pole nie ma wartości NULL. Na przykład:

 public DateTime MyDate { get; set; }

Zamień na:

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

2) Nowa baza danych ponownie. Na przykład:

db=new MyDb();
RainyTears
źródło
Co się stanie, jeśli nie chcesz domyślnie mieć wartości DateTime.Now?
Savage
Jeśli nie chcesz: DateTime.Now. Możesz użyć: nowego DateTime (..., ..., ...)
RainyTears,
0

Problem z odziedziczonym atrybutem daty i godziny

Ten komunikat o błędzie jest często wyświetlany, gdy pole daty, która nie ma wartości zerowej, ma wartość null w czasie wstawiania / aktualizacji. Jedną z przyczyn może być dziedziczenie.

Jeśli twoja data jest dziedziczona z klasy podstawowej i nie wykonasz mapowania, EF nie odczyta jego wartości.

Aby uzyskać więcej informacji: https://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-3-table-per-concrete-type-tpc-and- wytyczne dotyczące wyboru strategii

FrankyHollywood
źródło
0

Widziałem ten błąd, gdy chciałem edytować stronę przy użyciu ASP.Net MVC. Podczas tworzenia nie miałem problemu, ale aktualizacja bazy danych spowodowała, że ​​moja właściwość DateCreated była poza zasięgiem!

Jeśli nie chcesz, aby twoja DateTimewłaściwość miała wartość Nullable i nie chcesz sprawdzać, czy jej wartość należy do zakresu DateTime sql (i @Html.HiddenForto nie pomaga!), Po prostu dodaj static DateTimepole w pokrewnej klasie (Controller) i podaj jej wartość, gdy GET działa, a następnie użyj go, gdy POST wykonuje swoją pracę:

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");

    }
}
mp3846
źródło
0

Wystąpił ten problem w prostym projekcie aplikacji konsoli i moim szybkim rozwiązaniem jest przekonwertowanie wszelkich możliwych dat datetime2 na zerowy datetime, uruchamiając tę ​​metodę:

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

Z pewnością nie jest to całkowicie kompleksowa metoda, ale działała na moje potrzeby i być może pomoże innym!

David Alan Condit
źródło
0

Sprawdź format wymagań w DB. np. moja DB ma wartość domyślną lub Binding(((1)/(1))/(1900))

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

wprowadź opis zdjęcia tutaj

Arsalan Maqsood
źródło
-1

będziesz miał kolumnę daty, która została ustawiona tak, by zmniejszać minimalną wartość dozwolonego czasu, np. 1/1/1001.

aby przezwyciężyć ten problem, możesz ustawić odpowiednią wartość daty / godziny dla właściwości ur i ustawić inną magiczną właściwość, taką jak IsSpecified = true.

Koteshwar
źródło