EntityKey y ApplyPropertyChanges ()

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

Pregunta

Necesito establecer una EntityKey de EntityObject. Conozco su tipo y su valor de id. No quiero consultar la base de datos innecesariamente.

Esto funciona...

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

Esto falla ...

//
// 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 línea ApplyPropertyChanges () falla con esta excepción:

El ObjectStateManager no contiene un ObjectStateEntry con una referencia a un objeto de tipo 'Sample.Models.Department'.

Las dos EntityKeys son iguales. ¿Por qué falla el segundo bloque de código? ¿Cómo puedo arreglarlo?

Respuesta popular

La razón por la que falla el segundo bloque de código es porque EF no puede encontrar el objeto en el ObjectStateManager, es decir, cuando extrae objetos de la base de datos los coloca en el administrador de estado para que pueda rastrearlos. Esto es similar al patrón del Mapa de Identidad. . A pesar de tener una EntityKey, su objeto no está en el administrador del estado, por lo que EF no puede continuar con los cambios. Puede evitar esto colocando el objeto en el administrador de estado usted mismo, pero debe ser un poco disimulado al respecto.

Esto funciona:

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

... pero no está muy limpio. Básicamente, esto consiste en adjuntar un objeto 'vacío' con solo una clave de entidad, aceptar todos los cambios y luego llamar a ApplyPropertyChanges con los valores reales reales actualizados.

Aquí está lo mismo envuelto en un método de extensión: esto debería funcionar para cualquier cosa que haya usado una sola columna db para la clave principal. La única parte interesante de llamar al método es que necesita decirle cómo encontrar la propiedad clave a través de un delegado como el segundo argumento del método de extensión:

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

y el método de extensión:

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

Como el método de extensión es llamar a AcceptAllChanges, debe tener cuidado al llamar esto si está realizando actualizaciones en varias entidades a la vez; podría fácilmente "perder" las actualizaciones si no tiene cuidado. Por lo tanto, este enfoque solo es realmente adecuado para escenarios de actualización simples, por ejemplo, una gran cantidad de métodos de acción MVC :)



Related

Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué