EntityKey et ApplyPropertyChanges ()

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

Question

Je dois définir EntityKey d'un EntityObject. Je connais son type et son identifiant. Je ne veux pas interroger la base de données inutilement.

Cela marche...

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

Cela échoue ...

//
// 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 ligne ApplyPropertyChanges () échoue avec cette exception:

ObjectStateManager ne contient pas ObjectStateEntry avec une référence à un objet de type 'Sample.Models.Department'.

Les deux EntityKeys sont égaux. Pourquoi le second bloc de code échoue? Comment puis-je le réparer?

Réponse populaire

La raison pour laquelle votre deuxième bloc de code échoue est parce que EF ne peut pas trouver l'objet dans le ObjectStateManager - à savoir quand il tire des objets de la db il les met dans le gestionnaire de l' Etat afin qu'il puisse les suivre - ce qui est similaire à la carte d' identité modèle . Bien qu’il ait une EntityKey, votre objet n’est pas dans le gestionnaire d’états, EF ne peut donc pas conserver les modifications. Vous pouvez contourner cela en plaçant l'objet dans le gestionnaire d'état vous-même, mais vous devez être un peu sournois à ce sujet.

Cela marche:

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

... mais ce n'est pas très propre. Fondamentalement, il s’agit d’attacher un objet «vide» à une clé d’entité, d’accepter toutes les modifications, puis d’appeler ApplyPropertyChanges avec les valeurs réelles mises à jour.

Voici la même chose encapsulée dans une méthode d'extension - cela devrait fonctionner pour tout ce qui utilise une seule colonne de base de données pour la clé primaire. La seule partie intéressante de l'appel de la méthode est que vous devez lui dire comment trouver la propriété key via un délégué en tant que second argument de la méthode d'extension:

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

et la méthode d'extension:

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

Étant donné que la méthode d'extension appelle AcceptAllChanges, vous devez faire preuve de prudence lorsque vous effectuez des mises à jour simultanées sur plusieurs entités. Vous pouvez facilement perdre des mises à jour si vous ne faites pas attention. Par conséquent, cette approche ne convient vraiment que pour des scénarios de mise à jour simples - par exemple, beaucoup de méthodes d'action MVC :)



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi