Frage Entity Framework 5 Aktualisieren eines Datensatzes


Ich habe verschiedene Methoden zum Bearbeiten / Aktualisieren eines Datensatzes innerhalb von Entity Framework 5 in einer ASP.NET MVC3-Umgebung untersucht, aber bisher hat keines von ihnen alle Felder markiert, die ich brauche. Ich werde erklären warum.

Ich habe drei Methoden gefunden, auf die ich die Vor- und Nachteile anführen werde:

Methode 1 - Laden Sie den ursprünglichen Datensatz, aktualisieren Sie jede Eigenschaft

var original = db.Users.Find(updatedUser.UserId);

if (original != null)
{
    original.BusinessEntityId = updatedUser.BusinessEntityId;
    original.Email = updatedUser.Email;
    original.EmployeeId = updatedUser.EmployeeId;
    original.Forename = updatedUser.Forename;
    original.Surname = updatedUser.Surname;
    original.Telephone = updatedUser.Telephone;
    original.Title = updatedUser.Title;
    original.Fax = updatedUser.Fax;
    original.ASPNetUserId = updatedUser.ASPNetUserId;
    db.SaveChanges();
}    

Pros

  • Kann angeben, welche Eigenschaften sich ändern
  • Ansichten müssen nicht jede Eigenschaft enthalten

Nachteile

  • 2 x Abfragen in der Datenbank, um das Original zu laden und dann zu aktualisieren

Methode 2 - Laden Sie den ursprünglichen Datensatz, legen Sie die geänderten Werte fest

var original = db.Users.Find(updatedUser.UserId);

if (original != null)
{
    db.Entry(original).CurrentValues.SetValues(updatedUser);
    db.SaveChanges();
}

Pros

  • Nur geänderte Eigenschaften werden an die Datenbank gesendet

Nachteile

  • Ansichten müssen jede Eigenschaft enthalten
  • 2 x Abfragen in der Datenbank, um das Original zu laden und dann zu aktualisieren

Methode 3 - Aktuellen Datensatz anfügen und Status zu EntityState.Modified festlegen

db.Users.Attach(updatedUser);
db.Entry(updatedUser).State = EntityState.Modified;
db.SaveChanges();

Pros

  • 1 x Abfrage der zu aktualisierenden Datenbank

Nachteile

  • Kann nicht angeben, welche Eigenschaften sich ändern
  • Ansichten müssen jede Eigenschaft enthalten

Frage

Meine Frage an euch; Gibt es einen sauberen Weg, um diese Ziele zu erreichen?

  • Kann angeben, welche Eigenschaften sich ändern
  • Views müssen nicht jede Eigenschaft enthalten (zB Passwort!)
  • 1 x Abfrage der zu aktualisierenden Datenbank

Ich verstehe, dass dies eine ganz kleine Sache ist, auf die ich hinweisen muss, aber vielleicht fehlt mir eine einfache Lösung dafür. Wenn nicht Methode eins wird sich durchsetzen ;-)


811
2018-03-11 10:27


Ursprung


Antworten:


Du suchst nach:

db.Users.Attach(updatedUser);
var entry = db.Entry(updatedUser);
entry.Property(e => e.Email).IsModified = true;
// other changed properties
db.SaveChanges();

645
2018-03-11 13:12



Ich mag die angenommene Antwort sehr. Ich glaube, es gibt noch einen anderen Weg, dies zu erreichen. Nehmen wir an, Sie haben eine sehr kurze Liste von Eigenschaften, die Sie niemals in eine Ansicht aufnehmen möchten. Beim Aktualisieren der Entität würden diese also weggelassen. Nehmen wir an, dass diese beiden Felder Passwort und SSN sind.

db.Users.Attach(updatedUser);

var entry = db.Entry(updatedUser);
entry.State = EntityState.Modified;

entry.Property(e => e.Password).IsModified = false;
entry.Property(e => e.SSN).IsModified = false;   

db.SaveChanges();   

In diesem Beispiel können Sie Ihre Geschäftslogik im Wesentlichen alleine lassen, nachdem Sie der Tabelle "Benutzer" und der Ansicht ein neues Feld hinzugefügt haben.


168
2017-08-01 21:01



foreach(PropertyInfo propertyInfo in original.GetType().GetProperties()) {
    if (propertyInfo.GetValue(updatedUser, null) == null)
        propertyInfo.SetValue(updatedUser, propertyInfo.GetValue(original, null), null);
}
db.Entry(original).CurrentValues.SetValues(updatedUser);
db.SaveChanges();

27
2017-11-12 11:33



Ich habe eine zusätzliche Update-Methode für meine Repository-Basisklasse hinzugefügt, die der von Scaffolding generierten Update-Methode ähnelt. Anstatt das gesamte Objekt auf "modifiziert" zu setzen, legt es eine Reihe von individuellen Eigenschaften fest. (T ist ein generischer Klassenparameter.)

public void Update(T obj, params Expression<Func<T, object>>[] propertiesToUpdate)
{
    Context.Set<T>().Attach(obj);

    foreach (var p in propertiesToUpdate)
    {
        Context.Entry(obj).Property(p).IsModified = true;
    }
}

Und dann zum Beispiel anrufen:

public void UpdatePasswordAndEmail(long userId, string password, string email)
{
    var user = new User {UserId = userId, Password = password, Email = email};

    Update(user, u => u.Password, u => u.Email);

    Save();
}

Ich mag einen Ausflug in die Datenbank. Es ist jedoch wahrscheinlich besser, dies mit Ansichtsmodellen zu tun, um zu vermeiden, dass Sätze von Eigenschaften wiederholt werden. Ich habe das noch nicht gemacht, weil ich nicht weiß, wie ich vermeiden kann, die Validierungsnachrichten auf meinen View-Model-Validatoren in mein Domain-Projekt zu bringen.


21
2018-04-25 16:19



public interface IRepository
{
    void Update<T>(T obj, params Expression<Func<T, object>>[] propertiesToUpdate) where T : class;
}

public class Repository : DbContext, IRepository
{
    public void Update<T>(T obj, params Expression<Func<T, object>>[] propertiesToUpdate) where T : class
    {
        Set<T>().Attach(obj);
        propertiesToUpdate.ToList().ForEach(p => Entry(obj).Property(p).IsModified = true);
        SaveChanges();
    }
}

7
2018-03-16 16:04



Nur um zur Liste der Optionen hinzuzufügen. Sie können das Objekt auch aus der Datenbank abrufen und ein Auto-Mapping-Tool wie verwenden Automatische Zuordnung  um die Teile des Datensatzes zu aktualisieren, die Sie ändern möchten.


2
2017-12-03 15:58



Abhängig von Ihrem Anwendungsfall gelten alle oben genannten Lösungen. So mache ich es aber normalerweise:

Bei serverseitigem Code (z. B. einem Stapelprozess) lade ich normalerweise die Entitäten und arbeite mit dynamischen Proxies. In Batch-Prozessen müssen Sie die Daten normalerweise immer zum Zeitpunkt der Ausführung des Service laden. Ich versuche, die Daten im Stapel zu laden, anstatt die Methode find zu verwenden, um etwas Zeit zu sparen. Abhängig vom Prozess verwende ich optimistische oder pessimistische Gleichzeitigkeitskontrolle (ich verwende immer optimistisch, außer für parallele Ausführungsszenarien, wo ich einige Datensätze mit einfachen SQL-Anweisungen sperren muss, dies ist jedoch selten). Je nach Code und Szenario kann der Einfluss auf nahezu Null reduziert werden.

Für clientseitige Szenarien haben Sie einige Optionen

  1. Verwenden Sie Ansichtsmodelle. Die Modelle sollten eine Eigenschaft UpdateStatus (unmodified-inserted-update-deleted) haben. Es liegt in der Verantwortung des Kunden, abhängig von den Benutzeraktionen (insert-update-delete) den korrekten Wert für diese Spalte festzulegen. Der Server kann entweder die Datenbank nach den ursprünglichen Werten abfragen oder der Client sollte die ursprünglichen Werte zusammen mit den geänderten Zeilen an den Server senden. Der Server sollte die ursprünglichen Werte anhängen und die UpdateStatus-Spalte für jede Zeile verwenden, um zu entscheiden, wie mit den neuen Werten umzugehen ist. In diesem Szenario verwende ich immer optimistische Parallelität. Dies führt nur die Anweisungen insert - update - delete und nicht irgendwelche selects aus, aber es kann cleverer Code erforderlich sein, um das Diagramm zu durchlaufen und die Entitäten zu aktualisieren (abhängig von Ihrem Szenario - Anwendung). Ein Mapper kann helfen, aber nicht mit der CRUD-Logik umgehen

  2. Verwenden Sie eine Bibliothek wie "breeze.js", die den größten Teil dieser Komplexität verbirgt (wie in 1 beschrieben) und versuchen Sie, sie an Ihren Anwendungsfall anzupassen.

Ich hoffe es hilft


1
2018-05-30 12:07