Создание объекта домена из нескольких DTO

Предположим, у вас есть канонический объект домена Customer. У вас есть три разных экрана, на которых отображается Клиент: Внешний администратор, Внутренний администратор и Обновление учетной записи.

Предположим далее, что на каждом экране отображается только подмножество всех данных, содержащихся в объекте «Клиент».

Проблема в том, что когда пользовательский интерфейс передает данные обратно с каждого экрана (например, через DTO), он содержит только это подмножество полного объекта домена клиента. Поэтому, когда вы отправляете этот DTO в Customer Factory для воссоздания объекта Customer, у вас остается только часть Customer.

Затем вы отправляете этого клиента в свой репозиторий клиентов, чтобы сохранить его, и множество данных будет уничтожено, потому что его там нет. Наступает трагедия.

Возникает вопрос: как бы вы справились с этой проблемой?

Некоторые из моих идей:

  • включить аргумент в Репозиторий с указанием какой части Заказчик обновлять и игнорировать другие

  • когда вы загружаете клиента, храните его в статической памяти или в сеансе, или где-то еще, а затем, когда вы получаете один из DTO из пользовательского интерфейса, обновляйте только части, относящиеся к DTO

ИМО, оба эти клуджи. Есть ли другие идеи получше?

@chadmyers: Вот в чем проблема.

Сущность имеет свойства A, B, C и D.

DTO # 1 содержит свойства для B и C.

DTO # 2 содержит свойства для C и D.

Пользовательский интерфейс запрашивает DTO № 1, вы загружаете объект из репозитория, конвертируете его в DTO № 1, заполняя только B и C, и передаете его пользовательскому интерфейсу.

Теперь пользовательский интерфейс обновляет B и отправляет DTO обратно. Вы воссоздаете объект, и в нем заполнены только B и C, потому что это все, что содержится в DTO.

Теперь вы хотите сохранить объект, в котором заполнены только B и C, с пустыми / пустыми A и D. Репозиторий не имеет возможности узнать, следует ли обновлять A и D в постоянстве как пустые или игнорировать их.

Паттерн репозитория в laravel
Паттерн репозитория в laravel
Шаблон репозитория - это шаблон проектирования программного обеспечения, который обеспечивает уровень абстракции между приложением и уровнем...
4
0
2 469
4

Ответы 4

Это веб-приложение? Загрузите объект клиента из репо, обновите его из DTO, сохраните обратно. Мне это не кажется чем-то вроде лабиринта. :)

ОБНОВЛЕНИЕ: согласно вашим обновлениям (пример A, B, C, D)

Итак, я подумал, что когда вы загружаете объект, он имеет заполненные A, B, C и D. Если DTO № 1 обновляет только B и C, это нормально. A и D не затронуты (что является желаемой ситуацией).

Что репозиторий делает с обновлениями B & C, зависит от него. Например, если вы используете Hibernate / NHibernate, он просто выяснит это и выпустит обновление.

Тот факт, что в DTO № 1 есть только B и C, не означает, что вы должны также обнулить A и D. Просто оставьте их в покое.

Неважно, веб-приложение это или нет. И проблема в том, что нет "DTO", а есть другие, и ни один из них полностью не описывает Заказчика, а только его часть.

moffdub 24.10.2008 01:47

Это имеет значение, потому что, если он сохраняет состояние, вы можете использовать другой подход, чем частичный DTO, и это то, что я собирался исследовать. И неважно, полностью ли это описывает DTO, в этом нет необходимости.

chadmyers 24.10.2008 01:55

Вы правы, один из вариантов - изменить дизайн DTO. Я не упомянул ограничение, что дизайн DTO, вероятно, не в моих руках. Вы предлагаете, чтобы вместо отдельного класса DTO объект Customer реализовал интерфейс DTO?

moffdub 24.10.2008 04:13

Нет, я не говорил о редизайне DTO (хотя для не веб-приложения вы можете использовать подход, полностью основанный на различиях). Я говорю: вашему DTO не нужно отображать 1: 1 с вашими объектами, на самом деле, они не должны. Но вы также не должны пытаться создать целую сущность из DTO.

chadmyers 24.10.2008 10:32

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

chadmyers 24.10.2008 10:33

См. Пример в вопросе. Он не умещался в 300 символов.

moffdub 25.10.2008 02:17

@moffdub Ладно, думаю, я все ближе к пониманию. Я обновил свой ответ. Я думаю, вам может не хватать части о том, что "другие поля не нужно обнулять"

chadmyers 25.10.2008 20:40

Похоже, вы говорите о DTO, который представляет собой просто интерфейс, который реализует сущность. Либо так, либо вы предлагаете хранить загруженный объект в своего рода кеше, чтобы вы могли обновлять только B и C, когда обновленный DTO возвращается. Я на грани?

moffdub 26.10.2008 01:22

Я бы использовал factory для загрузки полного объекта клиента из репозитория после получения DTO. После этого вы можете обновить только те поля, которые были указаны в DTO.

Это также позволяет вам применять оптимистичный параллелизм к вашему клиенту, например, проверяя последнюю обновленную метку времени.

Интересный подход. Тем не менее, вы торгуете некоторой производительностью, потому что у вас есть два обращения к репозиторию вместо одного.

moffdub 24.10.2008 01:51

Остерегайтесь оптимизации выше уровня репозитория, потому что вы позволяете мысли об оптимизации БД просачиваться через абстракцию репозитория. Вы можете применить кэширование 2-го уровня или другие подобные методы позже, если производительность станет проблемой.

chadmyers 24.10.2008 01:56

Остерегайтесь оптимизации кода еще до того, как он заработает. Кроме того, если вам нужна каждая наносекунда пропускной способности, зачем вы используете объекты?

yfeldblum 25.10.2008 21:21

Вы правы, Джастис. Я был известен как предварительный оптимизатор. Я пытаюсь бросить курить.

moffdub 26.10.2008 02:29

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

  1. Гидратация объекта из репозитория с последующим преобразованием его в DTO - пустая трата усилий. Я предполагаю, что ваш DAL передает DTO в ваш репозиторий, который затем преобразует его в полноценный объект сущности. Поэтому преобразование его обратно в DTO кажется расточительным.

  2. Наличие нескольких DTO имеет смысл, если у вас есть страница результатов поиска, которая показывает большой объем записей и отображает только часть данных вашей сущности. В этом случае эффективно передать этой странице только те данные, которые ей нужны. Нет смысла передавать DTO, который содержит частичные данные, на страницу CRUD. Просто дайте ему полный DTO или даже полный объект сущности. Если он не использует все данные, ничего страшного.

Итак, основная проблема заключается в том, что я не думаю, что вам следует передавать данные на эти страницы, используя частичные DTO. Если бы вы использовали полный DTO, я бы сделал следующие 3 шага всякий раз, когда выполняется действие сохранения:

  1. Вытащить полный DTO из репозитория или базы данных
  2. Обновите DTO любыми изменениями, внесенными через форму
  3. Сохраните полный DTO обратно в репозиторий или базу данных

Этот метод требует дополнительного обращения к базе данных, но на самом деле это несущественная проблема для формы CRUD.

Если у нас есть понимание, что репозиторий обрабатывает (почти исключительно) очень богатый объектный объект, тогда вы можете просто отобразить множество DTO.

т.е.

dtoUser.MapFrom<In,Out>(Entity)
or
dtoAdmin.MapFrom<In,Out>(Entity)

вы бы сделали обратное, чтобы вернуть информацию о dto сущности и так далее. Таким образом, ваш репозиторий сохраняет только богатые Entity, НЕ многочисленные DTO

entity.Foo = dtoUser.Foo
or
entity.Bar = dtoAdmin.Bar

entityRepsotiry.Save(entity) <-- do not pass DTO.

Весь смысл DTO состоит в том, чтобы упростить презентацию или, скажем, для передачи данных WCF, это не имеет ничего общего с репозиторием или сущностью в этом отношении.

Кроме того, вы никогда не должны создавать Entity из DTO ... Единственные два способа когда-либо получить Entity - через Factory (новый) или репозиторий (существующий) соответственно.

Вы где-то упоминаете о хранении Entity, зачем вам это делать? Это работа вашего репозитория. Он решит, где взять Entity (db, cache, e.t.c), нет необходимости хранить его где-то еще.

Надеюсь, что это поможет распределить ответственность в вашем домене, это всегда проблема, и тут и там есть серые зоны, но в целом это типичное использование репозитория, DTO и т. д.

Другие вопросы по теме