EntityKey e ApplyPropertyChanges ()

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

Domanda

Devo impostare EntityKey di EntityObject. Conosco il suo tipo e il suo valore di identificazione. Non voglio interrogare il database inutilmente.

Questo funziona ...

//
// 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");
}

Questo fallisce ...

//
// 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");
}

La riga ApplyPropertyChanges () ha esito negativo con questa eccezione:

ObjectStateManager non contiene un oggetto ObjectStateEntry con un riferimento a un oggetto di tipo "Sample.Models.Department".

Le due EntityKeys sono uguali. Perché il secondo blocco di codice fallisce? Come posso ripararlo?

Risposta popolare

Il motivo per cui il tuo secondo blocco di codice fallisce è perché EF non riesce a trovare l'oggetto nell'ObjectStateManager - cioè quando estrae gli oggetti dal db li mette nello stato manager in modo che possa rintracciarli - questo è simile al pattern Mappa di identità . Nonostante abbia EntityKey, il tuo oggetto non è nel gestore dello stato, quindi EF non è in grado di mantenere le modifiche. È possibile aggirare questo mettendo l'oggetto nel gestore dello stato da soli, ma si è un po 'subdolo su di esso.

Questo funziona:

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

... ma non è molto pulito. Fondamentalmente si tratta di allegare un oggetto 'vuoto' con solo una chiave di entità, accettando tutte le modifiche e quindi chiamando ApplyPropertyChanges con i reali valori reali aggiornati.

Ecco la stessa cosa racchiusa in un metodo di estensione: questo dovrebbe funzionare per tutto ciò che utilizza una singola colonna db per la chiave primaria. L'unica parte interessante della chiamata del metodo è che devi dirgli come trovare la proprietà chiave tramite un delegato come secondo argomento del metodo di estensione:

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

e il metodo di estensione:

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

Poiché il metodo di estensione chiama AcceptAllChanges, dovresti stare attento a chiamare questo se stai facendo aggiornamenti su più entità contemporaneamente: potresti facilmente perdere gli aggiornamenti se non stai attento. Quindi questo approccio è veramente adatto solo per scenari di aggiornamento semplici, ad esempio molti metodi di azione MVC :)



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché