Die Konvertierung eines Datetime2-Datentyps in einen Datetime-Datentyp führt zu einem Wert außerhalb des Bereichs


379

Ich habe eine Datentabelle mit 5 Spalten, in der eine Zeile mit Daten gefüllt und dann über eine Transaktion in der Datenbank gespeichert wird.

Beim Speichern wird ein Fehler zurückgegeben:

Die Konvertierung eines Datetime2-Datentyps in einen Datetime-Datentyp führte zu einem Wert außerhalb des Bereichs

Beim Lesen bedeutet dies, dass meine Datentabelle einen Typ von DateTime2und meine Datenbank a hat DateTime. das ist falsch.

Die Datumsspalte ist DateTimewie folgt eingestellt :

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

Frage

Kann dies im Code gelöst werden oder muss etwas auf Datenbankebene geändert werden?

Antworten:


60

Welche Daten haben Sie in der Spalte?

Passen alle in den Bereich des Typs?


Abgesehen davon ist der richtige Weg, um ein TypeObjekt für den DataColumnKonstruktor zu erhalten, das typeofSchlüsselwort, das um Größenordnungen schneller ist.

Um die Spalte zu erstellen, sollten Sie daher schreiben

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

3
Ich habe meine Datenspalten geändert und jetzt typeof verwendet ... Außerdem habe ich mein Problem gefunden. Es gab 1 Datenzeile, die ein falsches Datum enthielt, was den Fehler auslöste
Gerbrand

739

Dies kann passieren, wenn Sie einem DateTime- Feld keinen Wert zuweisen , wenn das Feld keine NULL- Werte akzeptiert .

Das hat es für mich behoben!


43
Wenn Sie in Entity Framework eine erstellte Spalte hinzufügen, die nicht null ist, aktualisieren Sie Ihren EDMX, wenn Sie den Wert nicht im Code festlegen, der diesen Fehler auf diese Weise auslösen kann
Brad Thomas

6
Was hat es für Sie behoben? Dieser Fehler tritt auf, wenn Sie ein Datum / Uhrzeit-Feld mit einem Aufruf von getdate () als Standardwert haben.
user3046061

15
Warum kann das Entity Framework NULL nicht ignorieren, da ich auf meiner SQL-Seite den Standardwert = getdate () habe?
JoshYates1980

33
Ich glaube, dass EntityFramework einen DateTime.MinValue sieht, der das Jahr 0001 ist und in SQL datetime außerhalb des Bereichswertes liegt. Daher wird dieser Wert als DateTime2-Wert (der das Jahr 0001 unterstützt) gesendet, sodass das Einfügen / Aktualisieren jedoch gültig ist Es schlägt fehl, wenn SQL versucht, diese DateTime2 in eine DateTime zu konvertieren, da dies zu einem anderen Wert führt. Zwei Lösungen sind: 1 Verwenden Sie eine nullfähige Datums- / Uhrzeitangabe in Ihrem Modell oder 2. Initialisieren Sie alle Datums- / Uhrzeitwerte auf den richtigen Wert, bevor Sie Kontextänderungen speichern. Die Auswahl, die Sie treffen, hängt davon ab, was die Datums- und Uhrzeitangabe in Ihrem Modell bedeutet.
Guillermo Ruffino

1
@ GuillermoRuffinos Lösung hat bei mir funktioniert. Überprüfen Sie alle Ihre Felder und finden Sie diese 0001-Jahres-Einträge.
Francesco B.

158

Sowohl die DATETIMEals auch die DATETIME2Zuordnung zu System.DateTime.NET - Sie können keine "Konvertierung" durchführen, da es sich tatsächlich um denselben .NET-Typ handelt.

Siehe die MSDN-Dokumentseite: http://msdn.microsoft.com/en-us/library/bb675168.aspx

Es gibt zwei verschiedene Werte für das " SqlDbType" für diese beiden - können Sie diese in Ihrer DataColumnDefinition angeben ?

ABER: Unter SQL Server ist der unterstützte Datumsbereich ganz anders.

DATETIMEunterstützt 1753/1/1 bis "Ewigkeit" (9999/12/31), während DATETIME20001/1/1 bis Ewigkeit unterstützt.

Was Sie also wirklich tun müssen, ist das Jahr des Datums zu überprüfen. Wenn es vor 1753 liegt, müssen Sie es nach 1753 in etwas ändern, damit die DATETIMESpalte in SQL Server damit umgehen kann.

Marc


7
Dies erklärt das Problem, das ich hatte. Es gibt zwar nur wenige Situationen, in denen reale Daten vor 1753/1/1 behandelt werden müssen, aber es gibt viele Situationen, in denen der Standardwert 0001/1/1 angezeigt wird, der zu dem Fehler führen kann.
Hong

Ich bestätige, dass ich diese Ausnahme erhalten habe, als ich versucht habe, ein 'neues DateTime ()' in einen 'datetime'-Datentyp einzufügen.
George Onofrei

1
Ich habe versucht, einen Standardwert von DateTime.MinValue in meinem C # -Code zuzuweisen, der in eine Datenbank geschrieben wurde. Dies erklärt den Fehler, den ich bekommen habe. +1
Mkalafut

Ich verwende zuerst den Entity Framework-Code und das Modell mit der DateTime-Eigenschaft. DtInit = new System.DateTime(1492, 10, 12),schlägt fehl.
Kiquenet

Dies ist eine dieser Situationen, in denen der wahre Grund hinter dem Patch verborgen ist ... +1
Eugenio Miró

41

In meiner SQL Server 2008-Datenbank wurde eine DateTimeSpalte als nicht nullbar markiert, jedoch mit einer GetDate()Funktion als Standardwert. Beim Einfügen eines neuen Objekts mit EF4 wurde dieser Fehler angezeigt, weil ich keine DateTime-Eigenschaft für mein Objekt explizit übergeben habe. Ich habe erwartet, dass die SQL-Funktion das Datum für mich verarbeitet, aber das war nicht der Fall. Meine Lösung bestand darin, den Datumswert aus dem Code zu senden, anstatt sich bei der Generierung auf die Datenbank zu verlassen.

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

2
Froh, dass ich Helfen kann. Es ist ärgerlich, weil Sie denken, der EF-Datenkontext könnte feststellen, dass das Feld einen Standardwert hat, wenn das Objekt aus der Tabelle erstellt wird.
Graham

Ich würde viele Dinge über EF denken. Ich verwende die POCO-Self-Tracking-Entitäten und es ist so ein Cluster. Ich werde das erste Modell des Codes überprüfen, und wenn das auch voller Unsinn ist, denke ich ernsthaft darüber nach, zu Linq zu SQL zurückzukehren und einen Objekt-Mapper zu verwenden, um Requisiten meinen eigenen Entitäten

2
Ich habe vor 2 Wochen eine Demo von EF Code First bei VS Live gesehen und sie sah übrigens FANTASTISCH aus.
Graham

Das sind gute Neuigkeiten. Wir starten bald ein neues Projekt in meinem Büro und ich bin gespalten in EF-CF und Dapper (von SO verwendet / gewartet). Es wird wahrscheinlich darauf ankommen, was in einer App, die über einen WCF-Dienst verwendet wird, besser ist.

1
Hallo, jahrelange Kommentare! Ich selbst beginne mit EF Code-First und habe festgestellt, dass ich auf meinem POCO nur mein datetime-Mitglied als definieren musste Nullable<DateTime>, und im Code kann ich dies wirklich null lassen (anstelle des 01.01.0000). Ich war angenehm überrascht zu sehen, dass EF to SQL wusste, dass diese Null auf dem INSERT ignoriert und das Datum vom Server verwendet werden sollte ( GetDate()) ... Für uns war dies sogar vorzuziehen, da wir eine bessere Konsistenz auf dem Server benötigten, ohne uns um Taktunterschiede zwischen zu sorgen der Webserver und der des SQL-Servers.
Funka

34

für mich war es, weil die datetime war ..

01/01/0001 00:00:00

In diesem Fall möchten Sie Ihrem EF DateTime-Objekt null zuweisen ... am Beispiel meines FirstYearRegistered-Codes

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

Ich analysiere diese Daten mit ExcelDataReader und es wird der 01/01/0001 zurückgegeben, wenn ungültiger Text eingegeben wurde (löst nicht wie erwartet eine Ausnahme aus - mit der Methode .GetDateTime (columnIndex)). Der Vergleich mit dem MinValue hat dazu beigetragen, die Ausnahme außerhalb des Bereichs in SQL zu verhindern.
Tommy

22

Dieser machte mich verrückt. Ich wollte vermeiden, eine nullbare Datumszeit ( DateTime?) zu verwenden. Ich hatte auch nicht die Möglichkeit, den datetime2Typ von SQL Server 2008 zu verwenden

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

Ich entschied mich schließlich für Folgendes:

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
Verwenden [Column(TypeName = "datetime2")]?
Kiquenet

21

Manchmal weiß EF nicht, dass es sich um eine berechnete Spalte oder einen Trigger handelt . Diese Operationen setzen standardmäßig nach dem Einfügen einen Wert außerhalb von EF.

Der Fix besteht darin, Computedin EFs edmxfür diese Spalte in der StoreGeneratedPatternEigenschaft anzugeben .

Für mich war es, als die Spalte einen Auslöser hatte, der das aktuelle Datum und die aktuelle Uhrzeit einfügte, siehe unten im dritten Abschnitt.


Schritte zum Auflösen

Öffnen Sie in Visual Studio die Model BrowserSeite dann Modeldann Entity Types-> dann

  1. Wählen Sie die Entität und die Datums- / Uhrzeit-Eigenschaft aus
  2. Wählen StoreGeneratedPattern
  3. Einstellen Computed

Dialogfeld "EF-Modellbrowser-Modellentitätstyp"


In dieser Situation sind andere Antworten Problemumgehungen. In der Spalte wird zum Zeitpunkt der Erstellung des Datensatzes eine Uhrzeit / ein Datum angegeben. Dies ist die Aufgabe von SQL, einen Trigger auszuführen, um die richtige Zeit hinzuzufügen. Wie dieser SQL-Trigger:

DEFAULT (GETDATE()) FOR [DateCreated].


Beachten Sie, dass ich verwendet hatte, GETDATE()was ich damals buchstäblich tat. Aber es gab kürzlich einen Kommentar, den man SYSDATETIME()für alle DateTime2-Operationen verwenden sollte, von denen ich glaube, dass sie wahr sind.
ΩmegaMan

10

Ich bin darauf gestoßen und habe meiner datetime-Eigenschaft Folgendes hinzugefügt:

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

1
using System.ComponentModel.DataAnnotations.Schema; ist erforderlich
Kiquenet

9

Wenn wir kein Feld für Datum und Uhrzeit übergeben, wird das Standarddatum {01.01.0001 00:00:00} übergeben.

Dieses Datum ist jedoch nicht mit Entity-Frame-Arbeiten kompatibel, sodass die Konvertierung eines Datetime2-Datentyps in einen Datetime-Datentyp zu einem Wert außerhalb des Bereichs führt

Nur default DateTime.nowzum Datumsfeld, wenn Sie kein Datum übergeben.

movie.DateAdded = System.DateTime.Now

Ich würde sagen, dass das Übergeben von 'DateTime.Now' als Standardwert alles andere als korrekt und eher irreführend ist.
Bartosz

6

Am einfachsten wäre es, Ihre Datenbank so zu ändern, dass datetime2 anstelle von datetime verwendet wird. Die Kompatibilität funktioniert gut und Sie werden Ihre Fehler nicht bekommen.

Du wirst immer noch ein paar Tests machen wollen ...

Der Fehler liegt wahrscheinlich daran, dass Sie versuchen, ein Datum auf Jahr 0 oder so zu setzen - aber alles hängt davon ab, wo Sie die Kontrolle haben, um Dinge zu ändern.


4

Ich fand diesen Beitrag, um herauszufinden, warum ich immer wieder den folgenden Fehler bekam, der durch die anderen Antworten erklärt wird.

Die Konvertierung eines Datetime2-Datentyps in einen Datetime-Datentyp führte zu einem Wert außerhalb des Bereichs.

Verwenden Sie ein nullbares DateTime-Objekt.
public DateTime? Kaufdatum {get; einstellen; }}

Wenn Sie das Entity-Framework verwenden Setzen Sie die Eigenschaft nullable in der edmx-Datei auf True

Setzen Sie die nullable-Eigenschaft in der edmx-Datei auf ** True **


3

Wie andyuk bereits betont hat, kann dies passieren, wenn einem nicht nullbaren DateTime- Feld ein NULL- Wert zugewiesen wird . Betrachten Sie Ändern Datetime zu Datetime? oder Nullable < DateTime >. Beachten Sie, dass Sie bei Verwendung einer Abhängigkeitseigenschaft auch sicherstellen sollten, dass der Typ Ihrer Abhängigkeitseigenschaft ebenfalls ein nullfähiger DateTime-Typ ist.

Unten sehen Sie ein reales Beispiel für eine unvollständige DateTime to DateTime? Typanpassung, die das ungerade Verhalten erhöht

Geben Sie hier die Bildbeschreibung ein


2

Das Entity Framework 4 arbeitet mit dem Datentyp datetime2, sodass in db das entsprechende Feld datetime2 für SQL Server 2008 sein muss.

Um die Lösung zu erreichen, gibt es zwei Möglichkeiten.

  1. Um den Datetime-Datentyp in Entity Framwork 4 zu verwenden, müssen Sie das ProviderManifestToken in der edmx-Datei auf "2005" setzen.
  2. Wenn Sie das entsprechende Feld als Null zulassen festlegen (es konvertiert es in NULLABLE), verwendet EF automatisch Datumsobjekte als Datum / Uhrzeit.

1
Ich habe Ihren zweiten Punkt für meine Datenbankmodelle (POCO-Klassen) aufgegriffen und mich gefragt, wie ich ein Feld als nullbaren Typ festlegen kann. Falls sich jemand wundert, können Sie dies tun, indem Sie nach dem Datumstyp ein Fragezeichen (?) Einfügen. zB public DateTime? StartTime {get; einstellen; } Dies hat das Problem für mich gelöst. Das einzige, was ich tun musste, war, einen TimeSpan-Cast um eine Codezeile zu setzen, in der ich zwei nullbare DateTime-Werte voneinander subtrahierte. zB var timeTaken = (TimeSpan) (endTime - startTime);
Ciaran Gallagher

1

Erstellt eine Basisklasse basierend auf der Implementierung von @ sky-dev. Dies kann also leicht auf mehrere Kontexte und Entitäten angewendet werden.

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

Verwendungszweck:

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

Fügen Sie das unten angegebene Attribut für die Eigenschaft in Ihrer Modellklasse hinzu.

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

Anfangs habe ich vergessen, dieses Attribut hinzuzufügen. Also in meiner Datenbank wurde die Einschränkung wie folgt erstellt

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

und ich habe dieses Attribut hinzugefügt und meine Datenbank aktualisiert, dann wurde es in geändert

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

[DatabaseGenerated (DatabaseGeneratedOption.Computed)]
Ajith Chandran


0

Manchmal funktioniert es gut auf Entwicklungsmaschinen und nicht auf Servern. In meinem Fall musste ich sagen:

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

In der Datei web.config.

Die Zeitzone auf dem Computer (Server) war richtig (zum CO-Gebietsschema), die Web-App jedoch nicht. Diese Einstellung wurde vorgenommen und es hat wieder gut funktioniert.

Natürlich hatten alle Daten einen Wert.

: D.


0

Das Hinzufügen dieses Codes zu einer Klasse in ASP.NET hat für mich funktioniert:

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

0

Ich bin mir dieses Problems bewusst und Sie alle sollten es auch sein:

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

In SQL wurde ein neuer Feldtyp erstellt, um dieses Problem zu vermeiden (datetime2).

Dieser Feldtyp 'Datum' hat dieselben Bereichswerte wie eine DateTime .Net-Klasse. Es wird alle Ihre Probleme lösen, daher denke ich, dass der beste Weg, es zu lösen, darin besteht, Ihren Datenbankspaltentyp zu ändern (es hat keine Auswirkungen auf Ihre Tabellendaten).


0

Überprüfen Sie die folgenden zwei: 1) Dieses Feld hat keinen NULL-Wert. Zum Beispiel:

 public DateTime MyDate { get; set; }

Ersetzen:

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

2) Neue Datenbank erneut. Zum Beispiel:

db=new MyDb();

Was ist, wenn der Wert nicht standardmäßig DateTime.Now sein soll?
Savage

Wenn Sie nicht möchten: DateTime.Now. Sie können verwenden: new DateTime (..., ..., ...)
RainyTears

0

Problem mit dem geerbten datetime-Attribut

Diese Fehlermeldung wird häufig angezeigt, wenn ein nicht nullbares Datumsfeld zum Einfügen / Aktualisieren den Wert null hat. Eine Ursache kann die Vererbung sein.

Wenn Ihr Datum von einer Basisklasse geerbt wird und Sie keine Zuordnung vornehmen, liest EF den Wert nicht.

Für weitere Informationen: https://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-3-table-per-concrete-type-tpc-and- Auswahl-Strategie-Richtlinien


0

Ich habe diesen Fehler gesehen, als ich eine Seite mit ASP.Net MVC bearbeiten wollte. Ich hatte kein Problem beim Erstellen, aber beim Aktualisieren der Datenbank war meine DateCreated-Eigenschaft außerhalb des Bereichs!

Wenn Sie nicht möchten, dass Ihre DateTimeEigenschaft nullwertfähig ist, und nicht überprüfen möchten, ob ihr Wert im SQL-Bereich DateTime liegt (und @Html.HiddenFornicht hilft!), Fügen Sie einfach ein static DateTimeFeld innerhalb der zugehörigen Klasse (Controller) hinzu und geben Sie den Wert an, wenn GET ist in Betrieb und wird dann verwendet, wenn POST seine Aufgabe erfüllt:

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

Ich bin in einem einfachen Konsolen-App-Projekt auf dieses Problem gestoßen. Meine schnelle Lösung besteht darin, alle möglichen datetime2-Daten durch Ausführen dieser Methode in eine nullfähige datetime zu konvertieren:

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

Dies ist sicherlich keine vollständig umfassende Methode, aber sie hat für meine Bedürfnisse funktioniert und hilft vielleicht anderen!


0

Überprüfen Sie das Anforderungsformat in DB. zB hat meine DB Standardwert oder Bindung(((1)/(1))/(1900))

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

Geben Sie hier die Bildbeschreibung ein


-1

Sie haben eine Datumsspalte, die auf lesathan gesetzt wurde, den Mindestwert der zulässigen Zeit wie 1/1/1001.

Um dieses Problem zu beheben, können Sie den richtigen Datum / Uhrzeit-Wert auf Ihre Eigenschaft setzen und eine andere magische Eigenschaft wie IsSpecified = true festlegen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.