Повторное предприятие графика сущностей и обнаружение сбора изменений
-
25-10-2019 - |
Вопрос
Сначала я использую код фреймворта Entity и обнажаю базу данных Northwind через интерфейс WCF REST HTTP.
Я не разоблачал таблицу OrderDetails (пункты заказа), поскольку она не имеет смысла создавать заказ, а затем добавлять каждый требуемый OrderDetail отдельно через другую службу. На мой взгляд, это должна быть атомная транзакция, которая либо преуспевает, либо терпит неудачу как единый. Поэтому я включаю коллекцию Order.OrderDetails при передаче клиенту, и предполагаю, что собираюсь получить его, когда заказ будет создан или обновлен.
Однако проблема, по -видимому, определяет изменения в сборе OrderDetails при переборе объекта Order для обновления. Сам заказ может быть установлен как измененный для обновления этих свойств, но это не каскаднее для элементов OrderDetail. Таким образом, я могу вручную пройти и установить обновленные для изменения, но проблема заключается в выяснении, какие из них обновляются в первую очередь. Установка нового OrderDetail для изменения будет вызвать ошибку при попытке сохранить.
Я прочитал рекомендацию, чтобы установить идентификатор новых элементов коллекции на 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;
}
Решение
Это общая и сложная проблема И нет магии, которая сделает это для вас. Моим решением (и единственным, которое работает во всех сценариях) было загрузить 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, используемым для новых деталей и отрицательного идентификатора для удаленных деталей, но это логика, которая должна быть сделана на клиенте. Это также работает только в некоторых случаях.
Другие советы
Недавно мне разрешили открыть некоторую работу, которую я выполнил для своего работодателя некоторое время назад (конечно, с некоторыми изменениями). Я на самом деле написал метод расширения для решения этой проблемы, вы можете получить ее по http://refactorthis.wordpress.com/2012/12/11/introducing-graphdiff-for-entity-framework-code-first-allowing-automated-updates of-a-of-detached-entities/
Надеюсь, поможет!