Pregunta

Estoy usando el código de marco de Entity primero y exponiendo la base de datos Northwind a través de una interfaz HTTP REST WCF.

No he expuesto la tabla OrderDetails (elementos de pedido), ya que no tiene sentido crear un pedido y luego agregando cada pedido requerido por pedido por separado a través de otro servicio. En mi opinión, debe ser una transacción atómica que tenga éxito o falle como una sola. Por lo tanto, incluyo la colección Order. OrderDetails al pasar al cliente y supongo que voy a obtener uno cuando se cree o actualice un pedido.

Sin embargo, el problema parece ser detectar cambios en la colección OrderDetails al volver a colocar la entidad del pedido para una actualización. El pedido en sí se puede configurar como modificado para actualizar esas propiedades, pero esto no en cascada en los elementos de OrderDetail. Por lo tanto, puedo pasar manualmente y establecer los actualizados en modificado, pero el problema radica en determinar cuáles se actualizan en primer lugar. Establecer una nueva Cail de Order en Modificado causará un error al intentar guardar.

Leí una recomendación para establecer la ID de los nuevos elementos de colección en 0 y en el servidor usarlo para decidir si es nuevo o existente. Sin embargo, Northwind utiliza una clave compuesta entre OrderID y ProductId para OrderDetails. Ambos tendrán que ser establecidos por el cliente, por lo que no puedo encontrar una manera de detectar qué hay de nuevo. Además, un pedido eliminado no existirá en el gráfico separado y necesitaré descubrir qué se ha eliminado y eliminarlo explícitamente.

Cualquier consejo sería muy apreciado.

public override Order Update(Order entity)
{
    dbset.Attach(entity);
    DataContext.Entry(entity).State = EntityState.Modified;

    foreach (var orderDetail in entity.OrderDetails)
    {
        DataContext.Entry(orderDetail).State = EntityState.Modified;
    }

    return entity;
}
¿Fue útil?

Solución

Esto es problema común y complejo Y no hay magia que lo hará por ti. Mi solución (y la única que funciona en todos los escenarios) fue cargar el Order Nuevamente en su método de actualización y fusionar manualmente los cambios:

public override Order Update(Order entity)
{
    // No attach of entity

    var attached = DataContext.Orders.Include(o => o.OrderDetails).SingleOrDefault(...);
    if (attached == null) ...

    // Merge changes from entity to attached - if you change any property
    // it will be marked as modified automatically

    foreach (var detail in attached.OrderDetails.ToList())
    {
        // ToList is necessary because you will remove details from the collection

        // if detail exists in entity check if it must be updated and set its state

        // if detail doesn't exists in entity remove if from collection - if it is \
        // aggregation (detail cannot exists without Order) you must also delete it 
        // from context to ensure it will be deleted from the database
    }

    foreach (var detail in entity.OrderDetails)
    {
        // if it doesn't exists in attached create new detail instance,
        // fill it from detail in entity and add it to attached entity - 
        //you must not use the same instance you got from the entity
    }

    DataContext.SaveChanges();

    return entity;
}

También puede ser necesario verificar manualmente las marcas de tiempo si las usa.

El escenario alternativo es lo que ha descrito con 0 utilizado para nuevos detalles e ID negativos para detalles eliminados, pero esa es una lógica que debe hacerse en el cliente. También funciona solo en algunos casos.

Otros consejos

Recientemente se me ha permitido hacer un código abierto que hice para mi empleador hace un tiempo (con algunos cambios, por supuesto). De hecho, escribí un método de extensión para resolver este problema, puedes conseguirlo en http://refactorthis.wordpress.com/2012/12/11/introducing-graphdiff-for-entity-framework-code-first-averowing-automated-updates-of-a-Graph-detached-entities/

¡Espero eso ayude!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top