2008-10-23 7 views
4

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

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

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

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

Итак, вопрос: как бы вы справились с этой проблемой?

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

  • включает аргумент Repository, показывающий, какую часть Клиента обновить, и игнорировать других

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

IMO, оба из которых являются kludges. Есть ли другие лучшие идеи?

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

Сущность обладает свойствами А, В, С и D.

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

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

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

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

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

ответ

3

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

UPDATE: В соответствии с вашими обновлениями (пример A, B, C, D)

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

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

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

+1

Неважно, если это веб-приложение или нет. И проблема в том, что нет «DTO», но разных, и никто из них полностью не описывает Клиента, а лишь часть его. – moffdub

+0

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

+0

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

4

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

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

+0

Интересный подход. Вы, тем не менее, торгуете некоторой производительностью, потому что у вас есть два раунда поездки в репозиторий, а не один. – moffdub

+1

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

+1

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

1

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

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

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

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

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

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

1

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

т.е.

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

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

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

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

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

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

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

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