2012-04-05 9 views
5

He visto algunas de las respuestas a preguntas similares y realmente no parecen encajar con las mías.Adición de un nuevo objeto secundario mientras modifico el marco existente de entidad de niños

Estoy tratando de incorporar un patrón de Entity Framework: DbContext (página 90) y parece que no funciona. El código que estoy usando es el siguiente:

[HttpPost] 
public ActionResult Edit(Order order) 
{ 
    if (ModelState.IsValid) 
    { 
     db.Orders.Add(order); 
     db.Entry(order).State = EntityState.Modified; 

     foreach (var orderDetail in order.OrderDetails) 
     { 
       if (orderDetail.OrderId == 0) 
       { 
        db.Entry(orderDetail).State = EntityState.Added; 
       } 
       else 
       { 
        db.Entry(orderDetail).State = EntityState.Modified; 
       } 
       // The example order that I'm updating has two child entities 
       // so this orderId will be for the third, added one. 
       int addedOrderDetailId = order.OrderDetails[2].OrderId; 
      } 
      db.SaveChanges(); 
      return RedirectToAction("Index"); 
    } 

    ViewBag.CustomerId = new SelectList(db.Customers, "CustomerId", "CompanyName", order.CustomerId); 

    return View(order); 

} 

He estado corriendo un ejemplo donde el objeto Orden tiene dos objetos OrderDetail existentes y yo estoy tratando de añadir una tercera. Incluí la variable addOrderDetailId, para poder agregarlo a 'Watch' y ver cuándo cambió

Lo que he encontrado que está sucediendo es que OrderId del objeto OrderDetail agregado (que es 0 cuando el bucle foreach se ingresa) se está actualizando por el marco de la entidad al Id. de pedido del objeto Pedido. Esto sucede después de la primera iteración a través del bucle foreach (cuando la primera entidad hija cambia su estado a modificado. Esto significa que los tres elementos secundarios se marcan como modificados. Esto provoca que SaveChanges() intente actualizar una entrada en la base de datos que no existe.

Si alguien más ha tenido este problema, me complacería cualquier consejo para solucionarlo. También tendré que ocuparme de los objetos secundarios existentes que se eliminen, pero no han encontrado el momento de esto todavía, así que si alguien sabe de un patrón para esto, que también sería apreciada

Editar:.

Después de tomar el consejo de Slauma y la eliminación de db.Or ders.Add (orden). Pude mover la llamada a db.Entry (order) .State debajo del ciclo foreach. Esto me permitió recorrer el ciclo y establecer el estado de cada objeto OrderDetail modificado para los existentes y agregado para el agregado. Luego simplemente tuve que asignar el Id. De pedido del padre al Id. De pedido del niño y la actualización fue exitosa. También incluí el código que utilicé para eliminar objetos secundarios durante la edición. No estoy seguro de cuán eficiente es esto, pero funciona. Aquí está el código revisado:

[HttpPost] 
    public ActionResult Edit(Order order) 
    { 
     if (ModelState.IsValid) 
     { 
      List<int> previousProductIds = db.OrderDetails 
       .Where(ep => ep.OrderId == order.OrderId) 
       .Select(ep => ep.ProductId) 
       .ToList(); 

      List<int> currentProductIds = order.OrderDetails 
       .Select(o => o.ProductId) 
       .ToList(); 

      List<int> deletedProductIds = previousProductIds 
       .Except(currentProductIds).ToList(); 


      foreach (var deletedProductId in deletedProductIds) 
      { 
       OrderDetail deletedOrderDetail = db.OrderDetails 
        .Where(od => od.OrderId == order.OrderId && od.ProductId == deletedProductId) 
        .Single(); 

       db.Entry(deletedOrderDetail).State = EntityState.Deleted; 
      } 

      foreach (var orderDetail in order.OrderDetails) 
      { 
       if (orderDetail.OrderId == 0) 
       { 
        db.Entry(orderDetail).State = EntityState.Added; 
        orderDetail.OrderId = order.OrderId; 
       } 
       else 
       { 
        db.Entry(orderDetail).State = EntityState.Modified; 
       } 
      } 
      db.Entry(order).State = EntityState.Modified; 
      db.SaveChanges(); 
      return RedirectToAction("Index"); 
     } 
     ViewBag.CustomerId = new SelectList(db.Customers, "CustomerId", "CompanyName", order.CustomerId); 
     return View(order); 
    } 
+0

Gracias por la pregunta. En realidad, tu código me ayudó a dar una solución simple para actualizar o insertar hijos de una entidad. Cortar y pegar, trabajado por primera vez, trabajo hecho. +1 –

Respuesta

1

Poner esta línea de su código:

db.Orders.Add(order); 

esto va a poner el orden incluyendo todos OrderDetails en Added estado. La corrección de relación (que ocurre automáticamente en Add) configurará OrderId de todosOrderDetails en la clave de la orden. Cuando ingresa al bucle orderDetail.OrderId es != 0 para todos los artículos detallados y siempre ingresa la bifurcación que establece el estado en Modified. Ya no hay ningún artículo de OrderDetail en Added cuando termina el ciclo.

+0

Hola Slauma, gracias por la respuesta. Si elimino la línea db.Orders.Add (orden), la llamada que cambia el estado de la entidad Order a modified causa una violación de integridad referencial antes de que el código llegue al bucle foreach. Su respuesta, sin embargo, me permitió probar un enfoque diferente que funciona, que voy a colocar en una edición de mi pregunta original. – MickySmig

Cuestiones relacionadas