Mapeo de consulta a DTO con campos variables (Spring Boot)

soulsville

Buenas a todos,

os expongo la siguiente casuística con la esperanza de que me iluminéis con vuestro saber y conocimiento en aras de encontrar la mejor solución:

  • Supongamos que existe un DTO tipo Product que posee una serie de campos comunes a cualquier Product.
public class ProductblablaDTO {
	private String productNo
	private String categoryCode;
	private String material;

Existirán diferentes variaciones de este mismo DTO en función de la categoría de tal forma que ProductTipo2 tendrá una serie de campos a mayores que product tipo1, tipo3 o viceversa, es decir, existirá un DTO con campos comunes a todos los productos y otra serie de campos "dinámicos" en función del tipo.

Mi duda viene a la hora de abordar esta problemática de la forma más eficiente, ya que una posible solución sería añadir un campo tipo Map que contenga los campos dinámicos para cada tipo y rellenarlo "manualmente" con el resultado de una consulta:

List<Object> entityManager.createNativeQuery("blablabla")

Esto me parece una broza considerable, por lo que he estado investigando diferentes alternativas que puedan encajar como las etiquetas para Dynamic Mapping] de Hibernate, el deprecated de AliasResultTransformer, los Filters etc pero no termino de verlo.

¿Podríais indicarme cómo plantear la mejor solución para esto?
Gracias,

Ranthas

No termino de entender tu problema. ¿Quieres con una única consulta extraer un resultado que puede ser un producto de un tipo u otro?

Es decir, tienes todos los productos dentro de la misma tabla, pero dependiendo del tipo, rellenar un DTO u otro, ¿es ese el problema? Si es así, ¿has pensado en usar proyecciones?

1 respuesta
Camp1

No controlo de java, pero has pensado hacerlo por herencia? Al igual que tendrás la herencia definida en tus productos, hacer lo mismo con los DTO y por otra parte tener los mappers. Aprovecha el polimorfismo.

Un buen diseño en tus clases de productos es algo esencial que te va a simplificar muchísimo el trabajo.

1 respuesta
soulsville

#2 #3 Algo así. Sin embargo, con proyecciones puedo reducir la consulta a 1 pero utilizando N DTOs adicionales para cada tipo.... No sé qué será mejor.
La solución actual que tengo es la siguiente:

  • Tengo una cada consulta para cada categoría (10)
  • Dentro del DTO producto tengo un campo properties que es una colección de ObjectNode que almacena las propiedades extra para cada uno de los diferentes productos recibidos para cada consulta.
  • Este ObjectNode lo mapeo recorriendo el resultado de la consulta SQL recibiendo una lista de Tuples.

De esta forma consigo utilizar un único DTO que simplemente varía en ese campo, pero de todos modos no termina de convencerme demasiado la solución.
La alternativa que mencionáis #2 y #3 sería aplicar herencia, pero esto me obliga a generar sobre >10 objetos DTO más que extiendan la clase base ProductDTO, aunque quizá sea una solución más "limpia".

¿Cómo lo véis?

1 respuesta
B

Utiliza proyecciones como te han dicho. Cada uno de tus DTOs representa una proyección.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections (concretamente Class-based Projections)

Puedes usar también MapStruct, para facilitarte la vida con los mapeos entre dto y entity. Además esta librería funciona con polimorfismo.

B

Hibernate no ayuda en eso precisamente?

soulsville

Gracias por las respuestas.

No obstante, construir 10 DTOs para las variaciones de ProductoDTO también obliga al frontend (Angular6) a crear N interfaces ¿no? El asunto es que sobre una misma request devuelvo un DTO u otro al Front, por lo que se me replica el problema del mapping. Creo que esto me señala algún fallo en el diseño... ¿no?

JuAn4k4

¿ Has pensado que son todo productos con "cosas adicionales" que son solo info en plan name/description ?

Ranthas

#4 ¿Ese conjunto de propiedades no puedes almacenarlo en otra tabla y referenciarlo desde la tabla de Productos con una relación 1:N o M:N? Tendrías un único DTO con un atributo "properties" que sería una clase con toda la información encapsulada.

Así después en el front manejarías únicamente un DTO y solo tendrían que hacer la lógica correspondiente en función de esas propiedades.

También ayudaría un esquema de ejemplo de tu BBDD para hacernos una idea.

Usuarios habituales