EntityKey und ApplyPropertyChanges ()

.net asp.net-mvc c# entity-framework

Frage

Ich muss den EntityKey eines EntityObject festlegen. Ich kenne den Typ und den ID-Wert. Ich möchte die Datenbank nicht unnötig abfragen.

Das funktioniert...

//
// POST: /Department/Edit/5

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, Department Model)
{
    Model.EntityKey = (from Department d in db.Department
                       where d.Id == id
                       select d).FirstOrDefault().EntityKey;
    db.ApplyPropertyChanges(Model.EntityKey.EntitySetName, Model);
    db.SaveChanges();
    return RedirectToAction("Index");
}

Das scheitert ...

//
// POST: /Department/Edit/5

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, Department Model)
{
    String EntitySetName = db.DefaultContainerName + "." + Model.GetType().Name;
    Model.EntityKey = new System.Data.EntityKey(EntitySetName, "Id", Model.Id);
    db.ApplyPropertyChanges(Model.EntityKey.EntitySetName, Model);
    db.SaveChanges();
    return RedirectToAction("Index");
}

Die ApplyPropertyChanges () -Zeile schlägt mit dieser Ausnahme fehl:

Der ObjectStateManager enthält keinen ObjectStateEntry mit einem Verweis auf ein Objekt vom Typ 'Sample.Models.Department'.

Die beiden EntityKeys sind gleich. Warum schlägt der zweite Codeblock fehl? Wie kann ich es reparieren?

Beliebte Antwort

Der Grund für den Fehlschlag Ihres zweiten Codeblocks ist, dass EF das Objekt im ObjectStateManager nicht finden kann. Wenn also Objekte aus der Datenbank abgerufen werden, werden sie im Status-Manager abgelegt, sodass sie nachverfolgt werden können. Dies ähnelt dem Identity Map- Muster . Obwohl Sie einen EntityKey haben, befindet sich Ihr Objekt nicht im Zustandsmanager. EF kann also die Änderungen nicht beibehalten. Sie können dies umgehen, indem Sie das Objekt selbst in den Zustandsmanager legen, aber Sie sind ein wenig hinterlistig.

Das funktioniert:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, Department model)
{
  var entitySetName = db.DefaultContainerName + "." + model.GetType().Name;
  var entityKey = new System.Data.EntityKey(entitySetName, "Id", model.Id);

  db.Attach(new Department{Id = id, EntityKey = entityKey});
  db.AcceptAllChanges();

  db.ApplyPropertyChanges(entitySetName, model);
  db.SaveChanges();
}

... aber es ist nicht sehr sauber. Im Wesentlichen ist dies das Anhängen eines 'leeren' Objekts mit einem Entitätsschlüssel, das Akzeptieren aller Änderungen und das Aufrufen von ApplyPropertyChanges mit den tatsächlich aktualisierten Werten.

Das Gleiche gilt für eine Erweiterungsmethode - dies sollte für alles funktionieren, bei dem eine einzige Db-Spalte für den Primärschlüssel verwendet wird. Der einzige interessante Aspekt beim Aufruf der Methode ist, dass Sie ihr sagen müssen, wie sie die Schlüsseleigenschaft über einen Delegaten als zweites Argument der Erweiterungsmethode finden kann:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, Department model)
{
  db.ApplyDetachedPropertyChanges(model, x => x.Id);
  db.SaveChanges();
}

und die Erweiterungsmethode:

public static class EfExtensions
{
  public static void ApplyDetachedPropertyChanges<T>(this ObjectContext db, T entity, Func<T, int> getIdDelegate)
  where T : EntityObject
  {
    var entitySetName = db.DefaultContainerName + "." + entity.GetType().Name;
    var id = getIdDelegate(entity);
    var entityKey = new EntityKey(entitySetName, "Id", id);

    db.Attach(new Department {Id = id, EntityKey = entityKey});
    db.AcceptAllChanges();

    db.ApplyPropertyChanges(entitySetName, entity);
  }
}

Da die Erweiterungsmethode AcceptAllChanges aufruft, müssen Sie dies beim Aufrufen dieser Option mit Vorsicht ausführen, wenn Sie Aktualisierungen für mehrere Entitäten gleichzeitig durchführen. Wenn Sie nicht vorsichtig sind, können Sie Aktualisierungen leicht verlieren. Daher ist dieser Ansatz nur für einfache Aktualisierungsszenarien geeignet - z. B. viele MVC-Aktionsmethoden :)



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum