Rebinding an object graph and detecting collection changes

First, I use the entity structure code and expose the Northwind database through the WCF REST HTTP interface.

I did not set the OrderDetails table (order items), since it does not make sense to create an order, and then add each necessary OrderDetail separately through another service. In my opinion, it should be an atomic transaction that either succeeds or fails as one. Therefore, when transferring to the client, I include the Order.OrderDetails collection and assume that I will receive it when the order is created or updated.

However, the problem seems to be detecting changes in the OrderDetails collection when re-binding the Order object for updating. The order itself can be set as modified to update these properties, but this does not cascade OrderDetail elements. Therefore, I can manually switch and modify the updated ones, but the problem is to find out which ones are updated first. Setting a new modified OrderDetail parameter will result in an error when trying to save.

I read the recommendation to set the identifier of the new collection elements to 0 and use this on the server to determine if it is new or existing. However, Northwind uses the composite key between OrderID and ProductID for OrderDetails. Both must be installed by the client, so I cannot find a way to determine what's new. Also, the deleted OrderDetail will not exist in a separate column, and I will need to find out what was deleted and explicitly delete it.

Any advice would be highly appreciated.

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;
}
+5
source share
2 answers

, , . ( , ) , Order :

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

, .

- , 0 , , . .

+4

All Articles