Повторное присоединение графа сущностей и обнаружение изменений коллекции - PullRequest
5 голосов
/ 18 октября 2011

Сначала я использую код структуры сущностей и выставляю базу данных северного ветра через HTTP-интерфейс WCF REST.

Я не выставлял таблицу OrderDetails (элементы порядка), так как не имеет смысла создаватьOrder и затем добавление каждого необходимого OrderDetail отдельно через другой сервис.На мой взгляд, это должна быть атомарная транзакция, которая либо преуспевает, либо проваливается как единое целое.Поэтому я включаю коллекцию Order.OrderDetails при передаче клиенту и предполагаю, что получу ее при создании или обновлении заказа.

Однако проблема заключается в обнаружении изменений в коллекции OrderDetails при повторном присоединениисущность Order для обновления.Сам порядок может быть изменен для обновления этих свойств, но это не относится к элементам OrderDetail.Поэтому я могу вручную перейти и установить обновленные из них в измененные, но проблема заключается в том, чтобы выяснить, какие из них обновляются в первую очередь.Установка нового OrderDetail в измененное состояние приведет к ошибке при попытке сохранить.

Я прочитал рекомендацию установить Id новых элементов коллекции на 0 и на сервере использовать его, чтобы определить, является ли он новым или существующим.Однако Northwind использует составной ключ между OrderID и ProductID для OrderDetails.Они оба должны быть установлены клиентом, поэтому я не могу найти способ обнаружить, что нового.Кроме того, удаленный OrderDetail не будет существовать на отдельном графике, и мне нужно будет выяснить, что было удалено, и явно удалить его.

Любой совет будет высоко ценится.

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

Ответы [ 2 ]

6 голосов
/ 11 декабря 2012

Мне недавно разрешили открыть исходный текст работы, которую я сделал для своего работодателя некоторое время назад (с некоторыми изменениями, конечно). Я на самом деле написал метод расширения для решения этой проблемы, вы можете получить его на http://refactorthis.wordpress.com/2012/12/11/introducing-graphdiff-for-entity-framework-code-first-allowing-automated-updates-of-a-graph-of-detached-entities/

Надеюсь, это поможет!

4 голосов
/ 18 октября 2011

Это общая и сложная проблема , и нет магии, которая сделает это за вас.Мое решение (и единственное, которое работает во всех сценариях) состояло в том, чтобы снова загрузить 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, используемым для новых деталей, и отрицательным идентификатором для удаленных деталей, но это логика, которую необходимо выполнить на клиенте.Это также работает только в некоторых случаях.

...