«Незавершенный» POCO на клиенте. Могу ли я пополнить коллекции позже?

У меня есть настройка с Client -> WCF -> POCO -> EF4.

Скажем, у меня есть список с объектами A. Сущность A содержит среди других свойств огромный список сущностей B, которые не загружаются по умолчанию. Когда на клиенте выполняется определенное действие, ему может потребоваться знать список объектов B...

Если я загружаю объекты B для объекта A и присоединяю их к коллекции, объект A фактически изменяется, и я предполагаю, что при сохранении объекта он также сохранит эти «новые» объекты B в объект A?

Я мог бы подключить функцию GetEntityWithAllDetails, но тогда я получил бы некоторые данные, которые у меня уже есть, и если бы были другие коллекции, которые я не хотел бы загружать, это был бы полный беспорядок.

Вопрос можно свести к тому, как я могу повторно заполнить POCO на стороне клиента, когда у меня есть только частичный POCO для начала, и я хочу избежать двойной загрузки данных и при этом иметь возможность полагаться на EF4 для правильного сохранения сущности?


person rozon    schedule 23.03.2011    source источник


Ответы (2)


Это сложная задача, и EF с ней не справится — это ваша ответственность. Когда вы используете отсоединенные сущности, отслеживание изменений зависит от вас.

Ваше решение в настоящее время, вероятно, таково:

  • Клиент отправляет запрос в службу WCF
  • WCF использует EF для получения данных, закрытия контекста и возврата графа POCO или частичного графа обратно клиенту.
  • Клиент изменяет граф POCO/частичный граф и отправляет измененные данные обратно в службу WCF.
  • WCF создает новый контекст EF и сохраняет график POCO.

Звучит просто, но это не так. На последнем шаге вы должны вручную объяснить новому контексту, что изменилось. Обычно это означает интенсивное взаимодействие с ObjectStateManager (в случае ObjectContext API) или DbChangeTracker (в случае DbContext API). Это также означает, что вы должны передавать информацию об изменениях от клиента.

Например, предположим, что вы изменяете объект Order. Объект Order зависит от объекта Customer и имеет зависимых объектов OrderItem. Чтобы сделать это интересным, предположим, что OrderItems должны обрабатываться разными складами, чтобы каждый склад имел доступ только к назначенным ему элементам.

  • На первом этапе вы запросите Order с одного склада
  • На втором этапе вы уберете Order без Customer и с задержкой OrderItems.
  • На третьем шаге склад модифицирует несколько OrderItems по мере обработки. Удаляет один OrderItem из-за снятого с производства продукта и вставляет другой OrderItem для замены снятого с производства продукта. Из-за нехватки запасов некоторые позиции останутся без изменений. Склад отправляет Order обратно на сервер.
  • Что вы будете делать на четвертом шаге? Вы должны применить некоторые знания. Первое знание заключается в том, что клиент не был отправлен клиенту, поэтому вы не можете изменить отношения с клиентом. В случае отношения внешнего ключа это означает, что CustomerId нельзя изменить. Теперь вы должны явно указать, какая OrderItem была обновлена ​​(= существует в БД), какая не изменилась (= не требует никаких действий), какая была вставлена ​​(= должна быть вставлена) и худшая часть, которая была удалена (если вы этого не сделаете). t отправить некоторую информацию об удалении от клиента, вы не можете узнать ее без повторного ввода графа сущностей из базы данных).

По крайней мере, вы можете быть довольны тем, что EF не удалит ничего, что вы явно не пометили для удаления. Таким образом, позиции заказа, связанные с другими складами, и их связь с заказом не изменятся.

Есть два общих подхода, как с этим бороться:

Существует также совершенно отдельный подход к архитектуре с использованием DTO вместо прямых EF POCO, но это приводит к тем же сложностям, что и сейчас.

person Ladislav Mrnka    schedule 23.03.2011

Добро пожаловать в многоуровневую разработку.

Именно из-за такой ситуации многие решения корпоративного масштаба используют объекты передачи данных между уровнями.

Я бы порекомендовал избегать распространения объекта домена с сервисного (бизнес) уровня на клиент. Если вы пойдете по пути того, чтобы сущности узнавали, полностью ли они загружены или на каком уровне они в настоящее время находятся, вряд ли они являются «POCO», не так ли?

Итак, вы пишете служебный метод «GetEntityWithAllDetails». Он должен принимать объект GetEntityWithAllDetailsRequest и возвращать объект GetEntityWithAllDetailsResponse, содержащий все, что ожидает вызывающая служба, и не более того.

Очевидно, что между DTO и объектами предметной области необходимо выполнить большое количество сопоставлений — в этом могут помочь такие библиотеки, как Automapper (и другие).

Распространение сущностей домена на клиенте также ограничивает вашу гибкость в отношении ленивой или нетерпеливой загрузки сущностей и заставляет вас иметь дело с повторным присоединением/объединением сущностей, что является проблемой с EF, потому что он не будет повторно присоединять графы сущностей - вы должны пройтись по графику вручную.

Я постараюсь сказать это очень просто. Распространение сущностей предметной области от службы к клиенту — это дорога в программный ад и очень быстро приводит к тому, что объекты имеют всевозможные обязанности, которые не соответствуют их назначению.

person Xhalent    schedule 23.03.2011