¿Es una buena práctica usar objetos de entidad como objetos de transferencia de datos?


29

Me pregunto porque si es así, ¿por qué Entity Framework no ofrece lógica para crear un nuevo objeto con las mismas propiedades para transferir datos entre capas?

Utilizo los objetos de entidad que genero con el marco de la entidad.


3
Creo que esta es una buena pregunta, pero no puedo decirlo porque es muy difícil de leer y no estoy seguro de cómo solucionarlo. Por favor edite su pregunta.
candied_orange

1
@CandiedOrange +1, y hace que sea aún más aterrador que esto haya recibido tantos votos positivos.
guillaume31

Respuestas:


23

Es tu decision.

La mayoría de la gente le dirá que no es una buena práctica, pero puede salirse con la suya en algunos casos.

EF nunca jugó bien con DDD por múltiples razones, pero dos se destacan: no puede tener constructores parametrizados en sus entidades y no puede encapsular colecciones. DDD se basa en eso, ya que el modelo de dominio debe incluir tanto datos como comportamiento.

En cierto modo, EF te obliga a tener un modelo de dominio anémico y en este caso puedes usar las entidades como DTO. Puede encontrar algunos problemas si usa las propiedades de navegación, pero puede serializar esas entidades y enviarlas por cable. Sin embargo, puede no ser práctico. Deberá controlar la serialización de cada entidad que tenga propiedades que no necesita enviar. La forma más fácil es simplemente diseñar clases separadas adaptadas para la transferencia de datos. Las bibliotecas como AutoMapper se crean para este propósito.

Por ejemplo: suponga que tiene una clase llamada Personcon la siguiente definición:

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
}

Suponiendo que desee mostrar una lista de empleados en algún lugar, puede ser práctico enviar solo el Id, FirstNamey LastName. Pero tendrá que enviar todas las demás propiedades irrelevantes. No es un gran problema si no le importa el tamaño de la respuesta, pero la idea general es enviar solo los datos relevantes. Por otro lado, puede diseñar una API que devuelva una lista de personas y, en ese caso, puede ser necesario enviar todas las propiedades, por lo que tiene sentido serializar y enviar las entidades. En este caso, crear una clase DTO es discutible. A algunas personas les gusta mezclar entidades y DTO, a otras no.

Para responder a su pregunta actualizada, EF es un ORM. Su trabajo es mapear los registros de la base de datos a objetos y viceversa. Lo que haces con esos objetos antes y después de pasar por EF no es parte de sus preocupaciones. Tampoco debería ser.


1
Brevemente resumido. ¿Cuáles son las diferencias entre DTO y POCO? ¿No solo contienen datos?
Laiv

1
@ guillaume31 No puede tener un verdadero modelo de dominio sin tener en cuenta la persistencia. ¿De qué sirve una interfaz pública si me veo obligado a usar la reflexión (sin mencionar otro tipo de pirateo, siempre que mi propiedad pública esté respaldada por un campo privado con un nombre diferente) para cargar mis agregados en un estado válido? Si EF no me proporciona una infraestructura para ocultar mis agregados mediante el uso de su interfaz pública, entonces es mejor que mantenga mi lógica de negocios en otro lugar y tenga mi dominio anémico en lugar de escribir una placa de caldera adicional para cargarlos desde la base de datos.
devnull

1
Entonces, ¿preferiría hacer anémico todo su modelo de dominio que nombrar a su recolector de colecciones públicas de la misma manera que el campo privado? (Dejemos a un lado el problema del constructor, porque en la mayoría de los casos es contra el dominio, en primer lugar, exponer a un constructor que toma todos los campos del objeto ...)
guillaume31

1
@Konrad desde aquí : 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.me gusta mucho que me inyecten servicios de aplicaciones en mis entidades.
devnull

1
@ Konrad dejaría de usar mis entidades de dominio como DTO (si las usara de esta manera). Los DTO son útiles independientemente del soporte de EF para la inyección de servicio.
devnull

8

No, no es.

Idealmente, los DTO coincidirán con sus repositorios de persistencia (también conocidos como tablas de su base de datos).

Pero sus clases de negocios no son necesariamente una coincidencia. Es posible que necesite clases adicionales o clases separadas o unidas a lo que tiene en la base de datos. Si su aplicación es pequeña, es posible que no vea este tipo de problemas, pero en aplicaciones medianas a grandes, esto sucederá con frecuencia.

Otra cosa es que los DTO son parte del dominio de lo que sea que trate con persistencia, mientras que su Business Layer no debe saber nada sobre ellos.


Un objeto Command es un DTO del que la capa empresarial debería saber algo.
devnull

Creo que la capa empresarial probablemente llamará al objeto de comando indirectamente, a través de una interfaz. Y me refiero a los DTO como en los objetos simples que transportan datos, sin ninguna funcionalidad. No estoy seguro de si un objeto de comando es un DTO ( martinfowler.com/eaaCatalog/dataTransferObject.html ).
Juan Carlos Eduardo Romaina Ac

1
Por lo general, los comandos se separan en el comando real y su controlador. El comando contiene los datos, el controlador contiene el comportamiento. Cuando se usa así, la parte del comando solo contiene datos recibidos del cliente y actúa como un DTO entre el cliente y la capa empresarial.
devnull

Los DTO no fluyen de la persistencia al dominio, también pueden venir del exterior como en los datos que vienen (piense en las API REST). Como señaló devnull, los comandos y eventos son algo DTO y se transfieren a la capa empresarial. Si los controladores son de capa empresarial o no, depende del diseño.
Laiv

4

En realidad es una muy mala idea. Martin Fowler tiene un artículo sobre DTO locales .

En pocas palabras, DTOPattern se usó para transferir datos fuera del proceso, por ejemplo a través del cable y no entre capas dentro del mismo proceso.


Al igual que con todos los enfoques de programación, no hay una talla única para todos, de lo contrario no debatiríamos y discutiremos diferentes patrones y enfoques en cada aplicación que construyamos, simplemente siempre usaríamos las mismas cosas. Los DTO son esencialmente solo POPO, solo tienen nombres para mostrar alguna intención. No hay nada con el uso de un DTO para "transferir datos" entre, por ejemplo, servicio, controlador y a la vista. No hay nada en el nombre o la estructura de las clases que indiquen o limiten desde dónde se transfieren los datos
James

4

No, es una mala práctica.

Algunas razones:

  1. Los nuevos campos de entidad estarán en el Dto, por defecto . Usar la entidad significa que toda la información estará disponible para ser consumida por defecto. Esto puede llevarlo a exponer información sensible o, al menos, hace que su contrato de API se infle, con mucha información que no se usa para quién consume la API. Por supuesto, puede ignorar los campos utilizando algunas anotaciones (como @JsonIgnoredel mundo de Java), pero esto lleva al siguiente problema ...
  2. Muchas anotaciones / condiciones / controles en la entidad . Debe controlar lo que le gustaría enviar en Dto, cuando cambie el nombre de algún atributo (esto romperá el contrato), agregue algún atributo que no sea de la entidad, el orden de los atributos, etc. Pronto verá su simple entidad con muchas anotaciones, campos adicionales y cada vez será más difícil entender lo que está sucediendo.
  3. Menos flexibilidad . Con un Dto, puede dividir la información en más clases, cambiar los nombres de los atributos, agregar nuevos atributos, etc. No puede hacer esto tan fácilmente con una entidad como Dto.
  4. No optimizado . Su entidad siempre será más grande que un simple Dto. Por lo tanto, siempre tendrá más información para ignorar / serializar y probablemente se transmitirá más información innecesaria.
  5. Problemas perezosos . Usando la entidad de algunos marcos (como Hibernate), si intenta recuperar alguna información que no se cargó de forma diferida dentro de una transacción de base de datos antes, el proxy ORM no se adjuntará a la transacción y recibirá algún tipo de "excepción diferida" solo para llamar a un getmétodo de la entidad.

Por lo tanto, es más fácil y seguro usar algún tipo de herramienta de mapeador para ayudarlo en este trabajo, mapeando los campos de entidad a un Dto.


1

Para completar lo que dijo @Dherik, los principales problemas de usar objetos de entidad como objetos de transferencia de datos son:

  1. En una transacción, corre el riesgo de comprometer los cambios realizados en su entidad porque la usa como DTO (incluso si puede separar la entidad de la sesión en una transacción, la mayoría de las veces deberá verificar este estado antes cualquier modificación en su entidad-DTO y asegúrese de que no está en una transacción o que la sesión se ha cerrado si no desea que las modificaciones persistan).

  2. El tamaño de los datos que comparte entre el cliente y el servidor: a veces no desea enviar todo el contenido de una entidad al cliente para minimizar el tamaño de la respuesta de la solicitud. Separar el DTO de la entidad es más flexible, para especializar los datos que desea enviar en ciertos casos de uso.

  3. Visibilidad y mantenimiento: debe administrar sus anotaciones jpa / hibernate en los campos de su entidad y mantener las anotaciones jackson para serializar en json en el mismo lugar (incluso si puede separarlas de la implementación de la entidad al colocarlas en la interfaz heredada por el entidad). Luego, si cambia su contenido DTO al agregar un nuevo campo, otra persona probablemente pueda pensar que es un campo de la entidad, por lo tanto, un campo de la tabla en cuestión en su base de datos (incluso si puede usar la @Transientanotación en todos sus campos DTO para el caso ..!).

En mi opinión, crea ruido cuando lees la entidad, pero mi opinión es seguramente subjetiva.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.