Pergunta

Eu vi um monte de questões relacionadas ao mapeamento DTOs para objetos de domínio, mas Eu não senti que respondeu à minha pergunta. Eu usei muitos métodos antes e tenho minhas próprias opiniões, mas eu estou procurando algo um pouco mais concreto.

A Situação:

Temos muitos objetos de domínio. Nós estamos usando um modelo CSLA para que os nossos objetos de domínio pode ser bastante complexo e que contêm seu próprio acesso a dados. Você não quer passar estes ao redor do fio. Estamos indo para ser escrito alguns novos serviços que irá retornar os dados em vários formatos (.Net, JSON, etc.). Por esta (e outras razões) que também estão criando, um objeto de transferência de dados magra para passar ao redor no fio.

A minha pergunta é: como deve o DTO e objeto Domínio ser conectado

A minha primeira reacção é usar um Fowler, DTO-tipo de padrão solução . Eu vi este feito muitas vezes e ele se sente bem para mim. O objecto de domínio não contém qualquer referência ao DTO. Uma entidade externa (a "mapeador" ou "assembler") é chamado para criar um DTO a partir de um objeto de domínio. Normalmente há uma ORM no lado do objecto de domínio. A desvantagem desta situação é que o "mapeador" tende a ficar extremamente complexo para qualquer situação real e pode ser muito frágil.

Outra idéia colocar diante é para o objeto de domínio para "conter" o DTO, já que é apenas um objeto de dados magra. As propriedades do objeto de domínio seria internamente referência as propriedades DTO e só poderia retornar o DTO se pediu. Eu posso ver nenhum problema com isso, mas parece errado. Tenho visto alguns artigos onde as pessoas usando NHibernate apareceu para usar este método.

Existem outras maneiras? É uma das formas acima vale a pena usar? Se assim for, ou se não, porquê?

Foi útil?

Solução

A vantagem de ter um mapeador que fica entre o seu domínio e seu DTO não é tão appearent quando você só estão apoiando um único mapeamento, mas como o número de mapeamentos aumenta, tendo esse código isolado a partir do domínio ajuda a manter o domínio mais simples e mais magro. Você não vai ser bagunçando seu domínio com uma grande quantidade de peso extra.

Pessoalmente, eu tento e manter o mapeamento das minhas entidades de domínio e colocar a responsabilidade no que eu chamo de "camada Gestor / Serviço". Esta é uma camada que fica entre o aplicativo eo repositório (s), e fornece lógica de negócios, tais como a coordenação de fluxo de trabalho (Se você modificar A, você pode ter que também modificar B por isso o serviço Um vai trabalhar com o Service B).

Se eu tivesse um monte de possíveis formatos terminando, eu poderia olhar para criar um formatador plugable que poderia usar o padrão Visitor, por exemplo, para transformar meus entidades, mas eu não encontrei uma necessidade ainda por nada deste complexo.

Outras dicas

Você poderia usar um AutoMapper como a um escrito por Jimmy Bogard que não tem nenhuma conexão entre os objetos e se baseia em convenções de nomenclatura a ser cumpridos.

Nós usamos T4 modelos para criar as classes de mapeamento.

Pro - código legível disponíveis em tempo de compilação, mais rápido que um mapeador de tempo de execução. controlo de 100% sobre o código (pode usar o padrão parcial métodos / molde para estender a funcionalidade numa base ad-hoc)

Con -. Excluindo certas propriedades, coleções de objetos de domínio etc., aprender a sintaxe T4

Outra solução possível:. http://glue.codeplex.com

características:

  • mapeamento bidirecional
  • Mapeamento automático
  • Mapeamento entre diferentes tipos
  • mapeamento Nested e Flattening
  • Listas e matrizes
  • A verificação das relações
  • Teste o mapeamento
  • Propriedades, campos e métodos

Como você vê a implementar um construtor dentro da classe DTO que toma como parâmetro um objeto de domínio?

Say ... Algo como isto

class DTO {

     // attributes 

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

     // methods
}

Você também pode tentar Otis, um mapeador objeto-à-objeto. Conceitos são semelhantes aos mapeamento NHibernate (atributo ou XML).

http://code.google.com/p/otis-lib / wiki / GettingStarted

eu posso sugerir uma ferramenta que eu criei e é open source hospedado no CodePlex:. EntitiesToDTOs

Mapeamento do DTO para Entidade e vice-versa, é implementada por meio de métodos de extensão, estes compõem o Assembler laterais de cada extremidade.

Você termina com um código como:

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();

Por que não podemos fazer assim?

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 (ou) alguém: Por favor, sugerem. No exemplo acima, é ObjetoDoDomínio depende DTO. Desta forma eu posso evitar o código para fazer o mapeamento do dto <->. DomainObject

ou DomainObject classe pode estende a classe DTO?

Outra opção seria usar ModelProjector . Ele suporta todos os cenários possíveis e é muito fácil de usar com pegada mínima.

Podemos usar padrão de fábrica, Memento, e Builder para isso. Fábrica de esconder os detalhes sobre como criar instância de modelo de domínio do DTO. Memento vai cuidar da serialização / desserialização do modelo de domínio de / para o DTO e pode até mesmo acessar os membros privados. O construtor irá permite o mapeamento do DTO de domínio com interface fluente.

Manter o interior lógica de mapeamento de seus meios de entidade que o seu objeto de domínio agora está ciente de um "detalhe de implementação" que ele não precisa saber sobre. Geralmente, um DTO é a sua porta de entrada para o mundo exterior (a partir de uma solicitação de entrada ou através de uma leitura de um serviço / banco de dados externo). Desde a entidade é parte de sua lógica de negócio, é provavelmente melhor para manter esses detalhes fora da entidade.

Mantendo o mapeamento em outro lugar seria a única alternativa - mas onde deveria ir? Eu tentei introduzir mapeamento objetos / serviços, mas, depois de tudo foi dito e feito, parecia que overengineering (e provavelmente foi). Eu tive algum sucesso usando AutoMapper e tal para projetos menores, mas ferramentas como AutoMapper vêm com suas próprias armadilhas. Eu tive algumas bastante difícil encontrar questões relacionadas com mapeamentos porque mapeamentos de AutoMapper estão implícitos e completamente dissociado do resto do seu código (não como "separação de interesses", mas mais como um "onde faz o mapeamento godforsaken ao vivo") para que eles às vezes pode ser difícil de rastrear. Não quer dizer que AutoMapper não tem seus usos, porque ele faz. Eu só acho que o mapeamento deve ser algo que é tão óbvio e transparente possível para questões Evitar.

Em vez de criar uma camada de serviço de mapeamento, eu tive muito sucesso mantendo meus mapeamentos dentro dos meus DTOs. Desde DTOs sempre sentar-se no limite da aplicação, eles são podem ser feitas cientes do objeto de negócios e descobrir como mapear de / para eles. Mesmo quando o número de mapeamentos de escala para um montante razoável que funciona de forma limpa. Todos os mapeamentos estão em um só lugar e você não tem que gerenciar um monte de serviços de mapeamento interior de sua camada de dados, Anticorrupção da camada, ou camada de apresentação. Em vez disso, o mapeamento é apenas um detalhe de implementação delegada ao DTO envolvido com o pedido / resposta. Desde serializadores geralmente apenas propriedades serializar e campos quando você está enviando-o através do fio, você não deve correr em quaisquer problemas. Pessoalmente, eu encontrei esta a opção mais limpa e posso dizer, na minha experiência, ele se adapta bem a uma grande base de código.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top