2009-03-24 3 views
59

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

Ситуация:

У нас есть много объектов домена. Мы используем модель CSLA, поэтому наши объекты домена могут быть довольно сложными и содержать свой собственный доступ к данным. Вы не хотите передавать их по проводам. Мы собираемся написать несколько новых сервисов, которые возвратят данные в нескольких форматах (.Net, JSON и т. Д.). Для этого (и по другим причинам) мы также создаем обедненный объект передачи данных, чтобы пройти по проводам.

Вопрос в том, как должен быть подключен объект DTO и Domain?

Моя первая реакция заключается в использовании Fowler, DTO pattern-type solution. Я видел это много раз, и мне это кажется правильным. Объект домена не содержит ссылки на DTO. Для создания DTO из объекта домена вызывается внешний объект («сопоставитель» или «ассемблер»). Обычно на стороне объекта домена есть ORM. Недостатком этого является то, что «картограф» имеет тенденцию становиться чрезвычайно сложным для любой реальной ситуации и может быть очень хрупким.

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

Есть ли другие способы? Один из способов, над которым стоит использовать? Если да, то нет?

Спасибо за любое понимание заранее.

+2

Автомобиль выглядит интересным. Я видел много кода, прежде чем он заменит его. Моя основная проблема заключается в том, что если по какой-то причине я собираюсь застрять с тонкостью кода сопоставления, я бы предпочел сам контролировать ее. –

+2

Когда мы переходим из объектов DTOs_to_ Domain, это сопоставление на 100% вручную. Решить проблему гораздо труднее, поскольку мы стараемся не ограничивать использование наших объектов на основе операций, а не просто контейнерами данных. Идти _to_ a DTO, это непростая задача. –

+0

Я согласен с тем, что это неправильно, поскольку объект домена не должен знать объект dto. Хотя в этом случае они могут быть связаны, их назначение полностью раздельно (dtos обычно делается для цели), и вы создадите ненужную зависимость. – Sinaesthetic

ответ

33

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

Лично я пытаюсь сохранить отображение из своих объектов домена и возложить ответственность на то, что я называю «Уровень менеджера/службы». Это слой, который находится между приложением и хранилищем (-ями), и обеспечивает бизнес-логику, такую ​​как координация рабочего процесса (если вы изменяете A, вам, возможно, придется также изменить B, поэтому служба A будет работать с сервисом B).

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

22

Вы можете использовать automapper, такой как the one written by Jimmy Bogard, который не имеет связи между объектами и полагается на соглашения об именах.

+3

Automapper может привести к случайно обнаруженным свойствам -> дыре в безопасности. Было бы лучше сказать, что должно быть открыто как DTO. – deamon

+4

@deamon: действительная забота, но так же и ошибки (и потенциальные дыры в безопасности из-за человеческого контроля), которые могут быть созданы, записывая все эти коды коллизии. Я пойду автомагистральным путем и обработаю 5%, используя встроенную функцию пользовательского сопоставления. – Merritt

+0

@deamon - не можете ли вы просто выполнить условное сопоставление для тех свойств, которые вы не должны подвергать экспонату? Мышление AutoMapper обрабатывает этот сценарий? –

1

Другое возможное решение: http://glue.codeplex.com.

Особенность:

  • Двунаправленное отображение
  • Автоматического отображения
  • Преобразования между различными типами
  • Уплотненного картографированием и уплощением
  • Списков и массивами
  • Проверка отношений
  • Тестирования отображение
  • свойства, поля и методы
5

Мы используем шаблоны T4 для создания классов отображения.

Pro - человекообразный код, доступный во время компиляции, быстрее, чем среда выполнения. 100% контроль над кодом (может использовать частичные методы/шаблон шаблона для расширения функциональности на разовой основе)

Con's - исключая определенные свойства, коллекции объектов домена и т. Д., Изучая синтаксис T4.

0

Я предлагаю инструмент, который я создал, и с открытым исходным кодом размещен на CodePlex: EntitiesToDTOs.

Сопоставление с DTO на Entity и наоборот осуществляется с помощью методов расширения, они составляют сторону Ассемблера каждого конца.

Вы заканчиваете с кодом, как:

Foo entity = new Foo(); 
FooDTO dto = entity.ToDTO(); 
entity = dto.ToEntity(); 

List<Foo> entityList = new List<Foo>(); 
List<FooDTO> dtoList = entityList.ToDTOs(); 
entityList = dtoList.ToEntities(); 
+0

это архитектурно неправильно, потому что вы делаете DTO и сущностные сущности осведомленными друг о друге. – Raffaeu

+5

@ Raffaeu Я так не думаю, так как методы ToDTO/ToDTOs/ToEntity/ToEntities определены как методы расширения, которые представляют Ассемблеры. Логика преобразования сущности в DTO и наоборот применяется в методах расширения (Assemblers), а не в Entity/DTO. – kzfabi

+2

Если вы говорите об «Ассемблере», то реализуйте их правильно. Сделайте их модульными, сделайте их доступными с легкостью, используйте инъекцию зависимости. Не нужно, чтобы сама модель домена знала о преобразовании в DTO. Предположим, у меня есть 1 объект домена, но 50 разных приложений, использующих один и тот же домен, каждый из которых имеет собственный DTO. Вы не собираетесь создавать 50 расширений. Вместо этого вы создадите одну прикладную услугу для каждого приложения с необходимым ассемблером (ами), который вводится в качестве зависимости от службы. –

1

Как вы видите, чтобы реализовать конструктор внутри класса DTO, который принимает в качестве параметра объекта домена?

Say ... Что-то вроде этого

class DTO { 

    // attributes 

    public DTO (DomainObject domainObject) { 
      this.prop = domainObject.getProp(); 
    } 

    // methods 
} 
+6

Пожалуйста, никогда не делайте этого. Вы не хотите, чтобы ваш уровень DTO знал или зависел от вашего домена. Преимущество сопоставления заключается в том, что более низкие уровни можно легко отключить, изменив отображение, или что изменения на нижнем уровне могут быть управляющими путем изменения отображения. Скажем, dtoA-карты для domainObjectA сегодня, но завтра требование состоит в том, что оно сопоставляется с domainObjectB. В вашем случае вам нужно изменить объект DTO, который является большим нет-нет. Вы потеряли много преимуществ картографа. –

+1

Прежде всего, спасибо! : D. Итак, @FrederikPrijck, вставив слой между 'DTO' и' DomainObject', мы в основном стремимся, чтобы эта проблема DTO зависела от объекта домена, поэтому все «строительные работы» выполняются в среднем слое (классе) под названием ' mapper', который зависит как от DTO, так и от DomainObjects. Так что лучше всего или вообще рекомендую подход к этому вопросу? Я только прошу убедиться, что точка понята. – Victor

+4

Да, слой называется «Ассемблер». Используя 3-й уровень для определения сопоставлений, вы позволяете легко заменить уровень ассемблера другой реализацией (например: удалить Automapper и использовать ручные сопоставления), что всегда является лучшим выбором. Лучший способ понять это - подумать о том, где я дам вам Object A, а кто-то другой даст вам Object B. У вас нет доступа к каждому из этих объектов (только dll), поэтому сопоставление может быть выполнено только путем создания 3-го слой. Но даже если вы можете получить доступ к любому из объектов, сопоставления всегда должны выполняться вне, так как они не связаны. –

0

Почему не мы можем сделать, как это?

class UserDTO { 
} 

class AdminDTO { 
} 

class DomainObject { 

// attributes 
public DomainObject(DTO dto) { 
     this.dto = dto; 
}  

// methods 
public function isActive() { 
     return (this.dto.getStatus() == 'ACTIVE') 
} 

public function isModeratorAdmin() { 
     return (this.dto.getAdminRole() == 'moderator') 
} 

} 


userdto = new UserDTO(); 
userdto.setStatus('ACTIVE'); 

obj = new DomainObject(userdto) 
if(obj.isActive()) { 
    //print active 
} 

admindto = new AdminDTO(); 
admindto.setAdminRole('moderator'); 

obj = new DomainObject(admindto) 
if(obj.isModeratorAdmin()) { 
    //print some thing 
} 

@FrederikPrijck (или) кто-то: Просьба предложить. В приведенном выше примере DomainObject зависит от DTO. Таким образом, я могу избежать кода для создания сопоставления dto < -> domainobject.

или класс DomainObject может расширять класс DTO?