it-swarm.com.de

Hinzufügen von CreatedDate zu einer Entität mit Entity Framework 5 Code First

Ich versuche, Entitäten in meinem Model eine CreatedDate-Eigenschaft hinzuzufügen, und verwende EF5 Code First. Ich möchte, dass dieses Datum nicht einmal geändert wird. Ich möchte, dass es ein UTC-Datum ist. Ich möchte keinen Konstruktor verwenden, da ich viele Entitäten in meinem Modell habe, die ich von einer abstrakten Klasse erben möchte, die die CreatedDate-Eigenschaft enthält, und ich kann keinen Konstruktor mit einer Schnittstelle erzwingen.

Ich habe verschiedene Datenanmerkungen ausprobiert und versucht, einen Datenbankinitialisierer zu schreiben, der einen bestimmten Entitätstyp aufnimmt und eine Änderungsbeschränkung mit einem getdate()-Standardwert für den korrekten table_name und column_name schreibt, aber ich konnte diesen Code nicht schreiben korrekt.

Verweisen Sie mich nicht auf die AuditDbContext - Entity Framework-Überwachungskontexte oder die EntityFramework.Extended - Tools, da diese hier nicht das tun, was ich hier brauche.

UPDATE

Mein CreatedDate ist auf SaveChanges() null, da ich meiner Ansicht ein ViewModel übergeben habe, das zu Recht keine Audit-Eigenschaft mit dem Namen CreatedDate enthält. Und selbst wenn ich das Modell meiner Ansicht übergeben habe, bearbeite oder speichere ich CreatedDate nicht in der Ansicht.

Ich las hier , dass ich die [DatabaseGenerated(DatabaseGeneratedOption.Identity)] hinzufügen könnte, und dies würde EF sagen, dass CreatedDate nach Insert und Update korrekt gespeichert wird, jedoch nicht durch meine Anwendung geändert werden kann. Ich bekomme jedoch nur einen Cannot insert explicit value for identity column in table when IDENTITY_INSERT is set to OFF-Fehler, indem ich dieses Attribut hinzufüge .

Ich bin dabei, zu EF Model First zu wechseln, da diese einfache Datenbankanforderung in Code First zu implementieren lächerlich ist.

29
Brian Ogden

So habe ich es gemacht:

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime CreatedDate{ get; set; }

in der Up () -Methode meiner Migration:

AddColumn("Agents", "CreatedDate", n => n.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()"));
67
Rusty Divine

Überschreiben Sie die SaveChanges-Methode in Ihrem Kontext:

public override int SaveChanges()
{
  DateTime saveTime = DateTime.UtcNow;
  foreach (var entry in this.ChangeTracker.Entries().Where(e => e.State == (EntityState) System.Data.EntityState.Added))
   {
     if (entry.Property("CreatedDate").CurrentValue == null)
       entry.Property("CreatedDate").CurrentValue = saveTime;
    }
    return base.SaveChanges();

}

Aufgrund von Kommentaren aktualisiert : Nur für neu hinzugefügte Entitäten wird das Datum festgelegt.

28
Stephan Keller

Ähnlich wie Stephans's Answer aber mit Reflection und ignoriert auch alle (externen) Aktualisierungen der Benutzer. Show Gist

  public override int SaveChanges()
        {
            foreach (var entry in ChangeTracker.Entries().Where(x => x.Entity.GetType().GetProperty("CreatedTime") != null))
            {
                if (entry.State == EntityState.Added)
                {
                    entry.Property("CreatedTime").CurrentValue = DateTime.Now;
                }
                else if (entry.State == EntityState.Modified)
                {
                    // Ignore the CreatedTime updates on Modified entities. 
                    entry.Property("CreatedTime").IsModified = false;
                }

                // Always set UpdatedTime. Assuming all entities having CreatedTime property
                // Also have UpdatedTime
                // entry.Property("UpdatedTime").CurrentValue = DateTime.Now;
                // I moved this part to another foreach loop
            }

            foreach (var entry in ChangeTracker.Entries().Where(
                e => 
                    e.Entity.GetType().GetProperty("UpdatedTime") != null && 
                    e.State == EntityState.Modified || 
                    e.State == EntityState.Added))
            {
                entry.Property("UpdatedTime").CurrentValue = DateTime.Now;
            }

            return base.SaveChanges();
        }
4
guneysus

Ok, das Hauptproblem hier war, dass CreatedDate jedes Mal aktualisiert wurde, wenn ich SaveChanges anrief. Da ich CreatedDate nicht an meine Ansichten weitergegeben habe, wurde es von Entity Framework auf NULL oder MinDate aktualisiert.

Die Lösung war einfach, wissend, dass ich das CreatedDate nur einstellen muss, wenn EntityState.Added. Ich habe gerade mein entity.CreatedDate.IsModified = false gesetzt, bevor ich meine SaveChanges-Funktion überschreibe. Auf diese Weise habe ich die Änderungen von Updates ignoriert und ob es war Ein Hinzufügen des CreatedDate würde einige Zeilen später festgelegt.

4
Brian Ogden

Für EF Core finden Sie die von MS empfohlene Lösung hier: Standardwerte .

Verwenden Sie Fluent API in Ihrem DBContext:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Property(b => b.Created)
        .HasDefaultValueSql("getdate()");
}
1
Laobu

Code First bietet derzeit keinen Mechanismus zum Bereitstellen von Spaltenvorgabewerten.

Sie müssen die Basisklasse manuell ändern oder erstellen, um CreatedDate automatisch zu aktualisieren

public abstract class MyBaseClass
{
    public MyBaseClass()
    {
        CreatedDate = DateTime.Now;
    }
    public Datetime CreatedDate { get; set; }
}
1
Aiska Hendra