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?
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).
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; }
}
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();
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")
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.
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"));
}
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
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.
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.
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; }
}
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
Ich hatte das gleiche Problem und in meinem Fall habe ich das Datum auf DateTime () anstatt DateTime.Now gesetzt
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.
In meinem Fall passierte dies, wenn ich eine Entität verwendet habe und die SQL-Tabelle den Standardwert von datetime == getdate () .
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.
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.