É uma boa prática usar objetos de entidade como objetos de transferência de dados?


29

Gostaria de saber porque, se for, por que o Entity Framework não oferece lógica para criar um novo objeto com as mesmas propriedades para transferir dados entre camadas?

Eu uso os objetos de entidade que eu gero com a estrutura da entidade.


3
Eu acho que essa é uma boa pergunta, mas não sei dizer porque é tão difícil de ler que não tenho certeza de como corrigi-la. Edite sua pergunta.
candied_orange

1
@CandiedOrange +1, e isso torna ainda mais assustador o fato de ter recebido tantos votos positivos.
precisa

Respostas:


23

É com você.

A maioria das pessoas lhe dirá que não é uma boa prática, mas você pode se safar disso em alguns casos.

A EF nunca jogou bem com o DDD por várias razões, mas duas se destacam: você não pode ter construtores parametrizados em suas entidades e não pode encapsular coleções. O DDD depende disso, pois o modelo de domínio deve incluir dados e comportamento.

De certa forma, o EF obriga a ter um modelo de domínio anêmico e, nesse caso, você pode usar as entidades como DTOs. Você pode ter alguns problemas se usar as propriedades de navegação, mas poderá serializar essas entidades e enviá-las por fio. Pode não ser prático, no entanto. Você precisará controlar a serialização de cada entidade que possui propriedades que você não precisa enviar. A maneira mais fácil é simplesmente projetar classes separadas personalizadas para transferência de dados. Bibliotecas como o AutoMapper são criadas para esse fim.

Por exemplo: Suponha que você tenha uma classe chamada Personcom a seguinte definição:

public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; get; }

    // plus a bunch of other properties relevant about a person
}

Supondo que você queira exibir uma lista de funcionários em algum lugar, pode ser prático enviar apenas o Id, FirstNamee LastName. Mas você terá que enviar todas as outras propriedades irrelevantes. Não é um problema tão grande se você não se importa com o tamanho da resposta, mas a idéia geral é enviar apenas os dados relevantes. Por outro lado, você pode projetar uma API que retorne uma lista de pessoas e, nesse caso, o envio de todas as propriedades pode ser necessário, fazendo sentido serializar e enviar as entidades. Nesse caso, a criação de uma classe DTO é discutível. Algumas pessoas gostam de misturar entidades e DTOs, outras não.

Para responder sua pergunta atualizada, EF é um ORM. Seu trabalho é mapear os registros do banco de dados para objetos e vice-versa. O que você faz com esses objetos antes e depois de passar pelo EF não faz parte de suas preocupações. Nem deveria ser.


1
Resumidamente resumido. Quais são as diferenças entre DTOs e POCOs? Eles não guardam apenas dados?
LAIV

1
@ guillaume31 Você não pode ter um modelo de domínio verdadeiro sem levar em consideração a persistência. De que adianta uma interface pública se eu for obrigado a usar a reflexão (para não mencionar outros tipos de hacks, desde que minha propriedade pública seja apoiada por um campo privado nomeado diferentemente) para carregar meus agregados em um estado válido? Se a EF não estiver me fornecendo uma infraestrutura para hidratar meus agregados usando sua interface pública, é melhor manter minha lógica de negócios em outro lugar e ter meu domínio anêmico em vez de escrever uma placa de caldeira adicional para carregá-los do banco de dados.
21418 devnull

1
Então, você prefere tornar todo o seu modelo de domínio anêmico do que nomear seu getter de coleção pública da mesma maneira que o campo privado? (vamos definir o problema construtor de lado, porque é na maioria das vezes contra o domínio em primeiro lugar para expor um construtor de tomar todos os campos do objeto ...)
guillaume31

1
@ Konrad daqui : As of EF Core 2.1, only services known by EF Core can be injected. Support for injecting application services is being considered for a future release.eu gosto muito de ter serviços de aplicativos injetados em minhas entidades.
devnull

1
@ Konrad, eu pararia de usar minhas entidades de domínio como DTOs (se eu fosse usá-las dessa maneira). Os DTOs são úteis, independentemente do suporte da EF para injeção de serviço.
devnull 6/06/06

8

Não não é.

Idealmente, os DTOs corresponderão aos seus repositórios de persistência (também conhecidos como tabelas de banco de dados).

Mas suas classes de negócios não são necessariamente compatíveis. Você pode precisar de classes adicionais, separadas ou ingressadas no que você tem no banco de dados. Se seu aplicativo for pequeno, talvez você não veja esse tipo de problema, mas em aplicativos de médio a grande porte, isso acontecerá com frequência.

Outra coisa é que os DTOs fazem parte do domínio de qualquer coisa que lide com persistência, enquanto sua Camada de Negócios não deve saber nada sobre eles.


Um objeto de comando é um DTO sobre o qual a camada de negócios deve conhecer.
devnull

Acho que a camada de negócios provavelmente chamará o objeto de comando indiretamente, por meio de uma interface. E quero dizer DTOs como nos objetos simples que carregam dados, sem nenhuma funcionalidade. Não tenho certeza se um objeto de comando é um DTO ( martinfowler.com/eaaCatalog/dataTransferObject.html ).
Juan Carlos Eduardo Romaina Ac

1
Geralmente, os comandos são separados no comando real e em seu manipulador. O comando contém os dados, o manipulador contém o comportamento. Quando usada dessa maneira, a parte do comando contém apenas dados recebidos do cliente e atua como um DTO entre o cliente e a camada de negócios.
devnull

O DTO não flui da persistência para o domínio; eles também podem vir de fora, como nos dados que chegam (pense nas APIs REST). Conforme apontado por devnull, comandos e eventos são um pouco DTOs e são transferidos para a camada de negócios. Se os manipuladores são ou não uma camada de negócios, isso depende do design.
LAIV

4

Na verdade, é uma péssima ideia. Martin Fowler tem um artigo sobre DTOs locais .

Para encurtar a história, o DTOPattern foi usado para transferir dados para fora do processo, por exemplo, através do fio e não entre camadas dentro do mesmo processo.


Como em todas as abordagens de programação, não existe um tamanho único, caso contrário não debateríamos e discutiríamos diferentes padrões e abordagens em cada aplicação que criamos, sempre usamos as mesmas coisas. Os DTOs são essencialmente apenas POPOs, são apenas nomeados para mostrar alguma intenção. Não há nada em usar um DTO para "transferir dados" entre, por exemplo, serviço, controlador e visualização. Não há nada no nome ou na estrutura das classes que indique ou limite de onde e para os dados são transferidos
James

4

Não, é uma prática ruim.

Algumas razões:

  1. Novos campos de entidade estarão no Dto, por padrão . Usar a entidade significa que todas as informações estarão disponíveis para serem consumidas por padrão. Isso pode levar você a expor informações confidenciais ou, pelo menos, aumentar o contrato da API, com muitas informações que não são usadas para quem consome a API. Obviamente, você pode ignorar os campos usando algumas anotações (como @JsonIgnoreno mundo Java), mas isso leva ao próximo problema ...
  2. Muitas anotações / condições / controles na entidade . Você precisa controlar o que gostaria de enviar no Dto, quando algum nome de atributo foi alterado (isso interromperá o contrato), adicione algum atributo que não seja da entidade, a ordem dos atributos, etc. Em breve, você verá seu simples entidade com muitas anotações, campos extras e cada vez será mais difícil entender o que está acontecendo.
  3. Menos flexibilidade . Com um Dto, você é livre para quebrar as informações em mais classes, alterar os nomes dos atributos, adicionar novos atributos etc. Você não pode fazer isso tão facilmente com uma entidade como o Dto.
  4. Não otimizado . Sua entidade será sempre maior que um simples Dto. Portanto, você sempre terá mais informações a serem ignoradas / serializadas e provavelmente mais informações desnecessárias serão transmitidas.
  5. Problemas preguiçosos . Usando a entidade de algumas estruturas (como o Hibernate), se você tentar recuperar algumas informações que não foram carregadas com preguiça dentro de uma transação de banco de dados antes, o proxy ORM não será anexado à transação e você receberá algum tipo de "exceção preguiçosa" apenas para chamar um getmétodo da entidade.

Portanto, é mais fácil e seguro usar algum tipo de ferramenta de mapeamento para ajudá-lo nesse trabalho, mapeando os campos da entidade para um Dto.


1

Para concluir o que o @Dherik disse, os principais problemas do uso de objetos de entidade como objetos de transferência de dados são:

  1. Em uma transação, você corre o risco de confirmar as alterações feitas em sua entidade porque a usa como DTO (mesmo que você possa desanexar a entidade da sessão em uma transação, na maioria das vezes precisará verificar esse estado antes qualquer modificação no seu DTO da entidade e garanta que você não está em uma transação ou que a sessão foi encerrada se você não quiser que as modificações sejam persistentes).

  2. O tamanho dos dados que você compartilha entre o cliente e o servidor: às vezes você não deseja enviar todo o conteúdo de uma entidade para o cliente para minimizar o tamanho da resposta da solicitação. Separar o DTO da entidade é mais flexível, para especializar os dados que você deseja enviar em certos casos de uso.

  3. Visibilidade e manutenção: você precisa gerenciar as anotações jpa / hibernate nos campos da entidade e manter as anotações jackson para serializar no json no mesmo local (mesmo que você possa separá-las da implementação da entidade, colocando-as na interface herdada pelo entidade). Então, se você alterar o conteúdo do DTO ao adicionar um novo campo, outra pessoa provavelmente poderá pensar que é um campo da entidade, portanto, um campo da tabela em questão no seu banco de dados (mesmo que você possa usar a @Transientanotação em todos os seus campos do DTO para o caso ..!).

Na minha opinião, isso cria ruído quando você lê a entidade, mas minha opinião é certamente subjetiva.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.