it-swarm.com.de

Wie behebt man den Datetime2-Konvertierungsfehler außerhalb des gültigen Bereichs mit DbContext und SetInitializer?

Ich benutze die DbContext- und Code First-APIs, die mit Entity Framework 4.1 eingeführt wurden.

Das Datenmodell verwendet grundlegende Datentypen wie string und DateTime. Die einzige Annotation von Daten, die ich in einigen Fällen verwende, ist [Required], aber dies ist in keiner der DateTime-Eigenschaften enthalten. Beispiel:

public virtual DateTime Start { get; set; }

Die DbContext-Unterklasse ist ebenfalls einfach und sieht folgendermaßen aus:

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

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

Der Initialisierer setzt Datumsangaben im Modell entweder in diesem oder im nächsten Jahr auf sinnvolle Werte.

Wenn ich jedoch den Initialisierer starte, erhalte ich diesen Fehler bei context.SaveChanges():

Die Konvertierung von datetime2-Daten Typ zu einem Datetime-Datentyp resultierte in einem Wert außerhalb des Bereichs. Das Anweisung wurde beendet.

Ich verstehe nicht, warum das überhaupt passiert, weil alles so einfach ist. Ich bin auch nicht sicher, wie ich das Problem beheben kann, da es keine edmx-Datei zum Bearbeiten gibt.

Irgendwelche Ideen?

125
Alex Angas

Sie müssen sicherstellen, dass Start größer oder gleich SqlDateTime.MinValue (1. Januar 1753) ist. Start entspricht standardmäßig DateTime.MinValue (1. Januar 0001).

176
andygjp

Einfach . Setzen Sie zuerst den DateTime-Typ auf DateTime? . Damit Sie mit DateTime-Typ mit nullfähigem Inhalt in der Datenbank ..__ arbeiten können.

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; }
    }
20
Ulisses Ottoni

In einigen Fällen wird DateTime.MinValue (oder gleichwertig default(DateTime)) verwendet, um einen unbekannten Wert anzuzeigen. Diese einfache Erweiterungsmethode sollte helfen, das Problem zu lösen:

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

Verwendungszweck:

 DateTime? dateToPassOnToDb = tooEarlyDate.ToNullIfTooEarlyForDb();
19
Kjartan

Sie können das Feld auf Null setzen, wenn dies für Ihre spezifischen Modellierungsanliegen geeignet ist. Ein Nulldatum wird nicht in ein Datum umgewandelt, das nicht im Bereich des SQL-DateTime-Typs liegt, wie dies bei einem Standardwert der Fall wäre. Eine andere Möglichkeit ist die explizite Zuordnung zu einem anderen Typ, vielleicht mit,

.HasColumnType("datetime2")
12
Brian Kretzler

Obwohl diese Frage ziemlich alt ist und es bereits großartige Antworten gibt, dachte ich, ich sollte noch eine weitere Frage stellen, die drei verschiedene Ansätze zur Lösung dieses Problems erklärt.

1. Ansatz

Ordnen Sie DateTime-Eigenschaft public virtual DateTime Start { get; set; } explizit datetime2 in der entsprechenden Spalte der Tabelle zu. Standardmäßig wird EF es datetime zuordnen.

Dies kann durch fließende API oder Datenanmerkungen erfolgen.

  1. Fließende API

    Übergeben Sie in der DbContext-Klasse OnModelCreating und konfigurieren Sie die Eigenschaft Start (aus Gründen der Erklärung handelt es sich um eine Eigenschaft der EntityClass-Klasse).

    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. Datenanmerkung

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

2. Ansatz

Initialisieren Sie Start auf einen Standardwert im EntityClass-Konstruktor. Dies ist gut so, als würde der Wert von Start vor dem Speichern der Entität beim Start der Datenbank nicht festgelegt werden und immer einen Standardwert haben. Stellen Sie sicher, dass der Standardwert größer oder gleich SqlDateTime.MinValue ist (vom 1. Januar 1753 bis zum 31. Dezember 9999).

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

3. Ansatz

Start muss vom Typ nullfähig sein DateTime-note? nach DateTime-

public virtual DateTime? Start { get; set; }

Für weitere Erklärungen lesen Sie diese post

11
Aim

Meine Lösung bestand darin, alle datetime-Spalten auf datetime2 umzustellen und datetime2 für alle neuen Spalten zu verwenden. Mit anderen Worten, EF sollte standardmäßig datetime2 verwenden. Fügen Sie dies der OnModelCreating-Methode in Ihrem Kontext hinzu:

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

Das wird alle DateTime und DateTime bekommen? Eigenschaften für alle Ihre Entitäten.

8
Ogglas

Wenn Ihre DateTime-Eigenschaften in der Datenbank nullfähig sind, müssen Sie unbedingt DateTime? für die zugehörigen Objekteigenschaften verwenden. EF wird in DateTime.MinValue für nicht zugewiesene Werte übergeben.

6

initialisieren Sie die Start-Eigenschaft im Konstruktor

Start = DateTime.Now;

Dies funktionierte für mich, als ich versuchte, mit Hilfe von Code First ..__ einige neue Felder in die Users-Tabelle (AspNetUsers) von ASP .Net Identity Framework einzufügen Feld lastLogin vom Typ 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; }
    }
3

Basierend auf der Antwort von Benutzer @ andygjp ist es besser, wenn Sie die Methode base Db.SaveChanges() überschreiben und eine Funktion hinzufügen, um ein Datum zu überschreiben, das nicht zwischen SqlDateTime.MinValue und SqlDateTime.MaxValue liegt.

Hier ist der Beispielcode

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

Entnommen aus dem Kommentar von user @ sky-dev zu https://stackoverflow.com/a/11297294/915812

2
Hamza Khanzada

Ich hatte das gleiche Problem und in meinem Fall habe ich das Datum auf DateTime () anstatt DateTime.Now gesetzt

1
sam

Eine Zeile behebt dies:

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

Also fügte ich in meinem Code hinzu:

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

Das Hinzufügen dieser einen Zeile zum Abschnitt OnModelCreating zum Überschreiben der DBContext-Unterklasse sollte funktionieren.

0
Howie Krauth

In meinem Fall passierte dies, wenn ich eine Entität verwendet habe und die SQL-Tabelle den Standardwert von datetime == getdate () .

0
Ahmad Moayad

In meinem Fall schlugen meine Tests nach einigen Umgestaltungen in EF6 mit der gleichen Fehlermeldung wie das ursprüngliche Poster fehl, aber meine Lösung hatte nichts mit den DateTime-Feldern zu tun.

Beim Erstellen der Entität fehlte lediglich ein erforderliches Feld. Nachdem ich das fehlende Feld hinzugefügt hatte, wurde der Fehler behoben. Meine Entität hat zwei DateTime? Felder, aber sie waren nicht das Problem.

0
GrayDwarf

Ich verwende die Datenbank zuerst. Als dieser Fehler bei mir auftrat, bestand meine Lösung darin, ProviderManifestToken = "2005" in der edmx-Datei zu erzwingen (wodurch die Modelle mit SQL Server 2005 kompatibel wurden) Code zuerst.

0
Sérgio Azevedo