it-swarm.com.de

Entity Framework 5 Aktualisieren eines Datensatzes

Ich habe verschiedene Methoden zum Bearbeiten/Aktualisieren eines Datensatzes in Entity Framework 5 in einer ASP.NET MVC3-Umgebung untersucht, aber bisher hat keine von ihnen alle erforderlichen Kästchen angekreuzt. Ich erkläre warum.

Ich habe drei Methoden gefunden, zu denen ich die Vor- und Nachteile erwähnen werde:

Methode 1 - Originaldatensatz laden, jede Eigenschaft aktualisieren

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

Profis

  • 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 es dann zu aktualisieren

Methode 2 - Originaldatensatz laden, geänderte Werte einstellen

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

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

Profis

  • 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 es dann zu aktualisieren

Methode 3 - Aktualisierten Datensatz anhängen und Status auf EntityState.Modified setzen

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

Profis

  • 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 eine saubere Möglichkeit, diese Ziele zu erreichen?

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

Ich verstehe, dass dies eine Kleinigkeit ist, auf die ich hinweisen muss, aber ich vermisse möglicherweise eine einfache Lösung dafür. Wenn nicht Methode wird man sich durchsetzen ;-)

847
Stokedout

Du suchst nach:

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

Ich mag die akzeptierte Antwort wirklich. Ich glaube, dass es noch einen anderen Weg gibt, dies zu erreichen. Angenommen, Sie haben eine sehr kurze Liste von Eigenschaften, die Sie niemals in eine Ansicht aufnehmen möchten. Wenn Sie also die Entität aktualisieren, werden diese ausgelassen. 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 in Ruhe lassen, nachdem Sie Ihrer Benutzertabelle und Ihrer Ansicht ein neues Feld hinzugefügt haben.

174
smd
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();
28

Ich habe meiner Repository-Basisklasse eine zusätzliche Aktualisierungsmethode hinzugefügt, die der von Scaffolding generierten Aktualisierungsmethode ähnelt. Anstatt das gesamte Objekt auf "geändert" zu setzen, werden einzelne Eigenschaften festgelegt. (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 eine Reise in die Datenbank. Es ist jedoch wahrscheinlich besser, dies mit Ansichtsmodellen zu tun, um zu vermeiden, dass sich Sätze von Eigenschaften wiederholen. Das habe ich noch nicht getan, da ich nicht weiß, wie ich vermeiden kann, die Überprüfungsmeldungen auf meinen Ansichtsmodellüberprüfungen in mein Domänenprojekt zu übernehmen.

22
Ian Warburton
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();
    }
}
11

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

4
Bostwick

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

Für serverseitigen Code (z. B. einen Batch-Prozess) lade ich normalerweise die Entitäten und arbeite mit dynamischen Proxys. In der Regel müssen Sie in Batch-Prozessen die Daten ohnehin zum Zeitpunkt der Ausführung des Dienstes laden. Ich versuche, die Daten stapelweise zu laden, anstatt die Suchmethode zu verwenden, um Zeit zu sparen. Je nach Prozess verwende ich eine optimistische oder pessimistische Parallelitätssteuerung (ich verwende immer Optimismus, außer in parallelen Ausführungsszenarien, in denen ich einige Datensätze mit einfachen SQL-Anweisungen sperren muss, ist dies jedoch selten). Je nach Code und Szenario kann die Auswirkung auf nahezu null reduziert werden.

Für clientseitige Szenarien haben Sie einige Optionen

  1. Verwenden Sie Ansichtsmodelle. Die Modelle sollten eine Eigenschaft UpdateStatus (unverändert-eingefügt-aktualisiert-gelöscht) haben. Es liegt in der Verantwortung des Kunden, in Abhängigkeit von den Benutzeraktionen (Einfügen-Aktualisieren-Löschen) den richtigen 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 umgegangen werden soll. In diesem Szenario verwende ich immer optimistische Parallelität. Dies führt nur die Anweisungen zum Einfügen, Aktualisieren und Löschen aus und keine Auswahl. Möglicherweise ist jedoch ein geschickter Code erforderlich, um das Diagramm zu durchlaufen und die Entitäten zu aktualisieren (abhängig von Ihrer Szenarioanwendung). Ein Mapper kann helfen, behandelt aber nicht die CRUD-Logik

  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

3
Chriss