Andrés Guerra Montoya
Un atajo de teclado muy útil para copiar rápidamente líneas de código es ctrl+d
Rolando Mamani Salas
Justo estaba buscando esto Gracias
David Barrera
Joven usted me ha salvado
¿Cómo configurar un mapeador de elementos de compra en una API?
Explorar las técnicas y herramientas necesarias para trabajar con mapeadores en tu API puede parecer desafiante al principio, pero con un enfoque sistemático, este proceso puede simplificarse. En el caso de los mapeadores para elementos de compra, primero es crucial configurar un mapeador de elementos de compra eficiente, el cual te permitirá convertir entidades de compra de productos a objetos de tipo purchase item dentro de tu aplicación. Vamos a sumergirnos en el detalle del código para lograr estos objetivos.
@Mapper(componentModel = "spring") public interface PurchaseItemMapper { @Mappings({ @Mapping(source = "id.producto", target = "productId"), @Mapping(source = "cantidad", target = "quantity"), @Mapping(source = "estado", target = "active") }) PurchaseItem toPurchaseItem(CompraProducto compraProducto); @InheritInverseConfiguration @Mappings({ @Mapping(target = "compra", ignore = true), @Mapping(target = "producto", ignore = true), @Mapping(target = "id.compra", ignore = true) }) CompraProducto toCompraProducto(PurchaseItem item); }
¿Cómo configuro un mapeador para la entidad de compra completa?
El siguiente paso en nuestro viaje de mapeo implica la creación de un mapeador para la entidad de compra completa. Aquí aplicaremos conceptos similares para convertir una compra a un objeto de tipo purchase.
@Mapper(componentModel = "spring", uses = { PurchaseItemMapper.class }) public interface PurchaseMapper { @Mappings({ @Mapping(source = "idCompra", target = "purchaseId"), @Mapping(source = "idCliente", target = "clientId"), @Mapping(source = "fecha", target = "date"), @Mapping(source = "medioPago", target = "paymentMethod"), @Mapping(source = "comentario", target = "comment"), @Mapping(source = "estado", target = "state"), @Mapping(source = "productos", target = "items") }) Purchase toPurchase(Compra compra); List<Purchase> toPurchases(List<Compra> compras); @InheritInverseConfiguration @Mapping(target = "cliente", ignore = true) Compra toCompra(Purchase purchase); }
¿Qué beneficios ofrecen los mapeadores en sistemas de compras?
Los mapeadores maximizan la eficiencia en el manejo de conversiones entre entidades complejas en una API. Al implementar mapeadores:
@Mapper, se habilita la inyección de estas interfaces donde sea necesario, optimizando el flujo de trabajo.¿Cómo configuro adecuadamente las anotaciones y métodos?
Las anotaciones son esenciales para definir correctamente los flujos de conversión. Utilizando @Mappings y @Mapping, es posible especificar claramente qué atributos se transfieren o ignoran durante la conversión. También es crucial entender el uso de @InheritInverseConfiguration para invertir configuraciones previamente definidas, lo que potencia la reutilización de código y evita redundancias.
Consejos para una implementación exitosa
Avanzar en el robusto campo de la gestión de compras requiere habilidades con herramientas modernas para mapeo de datos. Con esta guía y ejemplos de código, te estarás posicionando para asegurar una integración eficaz y fluida en tus aplicaciones. ¡Ánimo y adelante!
Andrés Guerra Montoya
Un atajo de teclado muy útil para copiar rápidamente líneas de código es ctrl+d
Rolando Mamani Salas
Justo estaba buscando esto Gracias
David Barrera
Joven usted me ha salvado
William Moreno
Rolando Mamani Salas
Muy bien.
Cristian David Restrepo Marin
👍
Cristian Aguayo Forteza
Les quiero comentar que tuve un problema con la actualización de lo siguiente:
@Mapping(source = "productos", target = "items" ), (al autocompletar luego de cambiar item por items INTELLIJ no actualizaba el auto completar con ITEMS tuve que volver a la clase Purchase.java y quitar el método y volver a generar el getter an setter algo paso con el INTELLIJ. Por si a alguien mas le pasa para que pueda saber como solucionarlo. :)
Alexandra Serna Cardona
A mí me pasó lo mismo y lo "solucioné" igual que tú. También me pasó que el autocompletar, para @Mapping(source="id.idProducto", ...), no me detectaba el autocompletado de idProducto y hasta ahora no lo he solucionado, ¿encontraste alguna solución general para tu caso?
Rolando Mamani Salas
Entendido
Yo tuve un problema con esto; cuando cree los getters y setters para el atributo "compra" dentro de ComprasProducto, el setter lanzaba un error sobre this.compra: "Cannot access com.platzi.platzimarket.persistence.entity.Compra". Si elimino el setter, la app corre, pero siento que es porque en el PurchaseItemMapper se está ignorando compra en el reverse mapping (ver video en 5:32) . De remate, nunca me autocompletó nada el MapStruct... alguien tiene idea de que está pasando?
Christian Acevedo
Yo uso Lombok para evitar escribir los getter and setter, esto es una buena practica?
Rolando Mamani Salas
Creo que no por que es una dependencia obsoleta
Jean Michael Lozano Cardoso
Desde que no interfiera (no lo hace) con el proyecto, lo puedes usar con confianza
David Gallego
En la clase destino siempre deben hacerse todos los mappings, si no se tienen todos los atributos mapeados, se tienen que ignorar explícitamente
Alejandro Ramírez
ProfesorSí bien lo explico así porque me gusta tener control visual de todos los atributos a la hora de mapearlos, también podrías agregar el parámetro unmappedTargetPolicy = ReportingPolicy.IGNORE en la anotación @Mapper para no tener que ignorarlos explícitamente en los métodos con ignore = true. Por ejemplo, para el PurchaseMapper sería algo así:
@Mapper(..., unmappedTargetPolicy = ReportingPolicy.IGNORE) public interface PurchaseMapper { ... }
Quinto Impacto
incluso recomiendo agregar el parametro "unmappedTargetPolicy = ReportingPolicy.ERROR", que hace saltar un error en tiempo de compilación en caso de que te haya faltado mapear alguna relación o ignore específico. Ayuda mucho para evitar dolores de cabeza después cuando alguna consulta no se comporta como esperamos
Juan Manuel Meneses Ibarra
El agregar una lista en un Optional se considera un Code Smell, debido a que si no hay datos nos regresa una lista vacía.
Quinto Impacto
es verdad, pero podes hacer algo como esto para asegurarte de que el optional se devuelva vacio si contiene un listado sin elementos:
public Optional<List<ProductDto>> getByCategory(long categoryId) { return productRepo.getByCategory(categoryId) .filter(prods -> !prods.isEmpty()); } ```llamando al metodo .filter del opcional, podes filtrar el contenido para incluirlo solo si tiene elementos. el optional retornado entonces es el mismo si existen elementos dentro de la lista, o un optional vacio en caso de haber contenido una lista vacia.
Tara Campos Padilla
Yeferson Yuberley Guerrero Castro
Si tiene un error que dice
Unknown property "compra" in result type ComprasProducto. Did you mean "total"?
David Barrera
Joven excelente aporte!
Ivan Santiago Barrera Medina
Alguien sabe como solucionar este error de la consola de Spring cuando se hace la petición Http desde Postman?
Caused by: java.io.StreamCorruptedException: invalid stream header: 33313034
Ricardo Proaño
he visto que hay como pagina las listas ya que si trabajamos con 10 o 100 elementos es rapido en frontend pero si hablamos 1000 ya comienza a hacerse lento como puedo hacer esto com mapping
Alejandro Ramírez
ProfesorSpring Data soporta los paginadores al momento de crear nuestros Query Methods. Asimismo, sí el dto tambien tiene paginador, MapStruct haría esta conversión automáticamente.
Puedes probar y me dices que tal te va.
Jhon Erick Montaño
buenas noches me gustaria preguntar si alguen le ha marcado este error:
Failed to initialize JPA EntityManagerFactory: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.sql.ast.tree.from.UnknownTableReferenceException: Unable to determine TableReference (productos) for com.platzi.market.persistence.entity.Compra.productos.{fk-target}
Jesus Peche
En la parte de persistence> Entity..
@OneToMany(mappedBy = "producto") private List<ComprasProducto> productos;
Cambia el nombre del campo por el atributo que se hace la relacion
@OneToMany(mappedBy = "compra") private List<ComprasProducto> productos;
Tara Campos Padilla
En el inverse no se repite la anotacion @Mappings:
@InheritInverseConfiguration @Mapping(target="compra",ignore = true) @Mapping(target="producto",ignore = true) @Mapping(target="id.idCompra",ignore = true) ComprasProducto toComprasProducto(PurchaseItem item);
Ricardo Legger
tengo una duda.... la interfaces se debe de declarar como por ejemplo ICategoryMapper.java, debe de hacerse así?
Alexis Duque
Si así debe ser para mantener un standar
Yhon Barrios Gandara
buen curso se aprende bastante
Christopher Joel Delvicier Palacios
Asi sea para ignorarlo, pero lo vamos a usar, pobresito xD
Alfonso Barcelo
¡Excelente!
Cristian David Restrepo Marin
@Mapper(componentModel = "spring", uses = {PurchaseItemMapper.class}) public interface PurchaseMapper { @Mappings({ @Mapping(source = "idCompra", target = "purchaseId"), @Mapping(source = "idCliente", target = "clienteId"), @Mapping(source = "fecha", target = "date"), @Mapping(source = "medioPago", target = "paymentMethod"), @Mapping(source = "comentario", target = "comment"), @Mapping(source = "estado", target = "state"), @Mapping(source = "productos", target = "items"), }) Purchase toPurchase(Compra compra); List<Purchase> toPurchases(List<Compra> compras); @InheritInverseConfiguration @Mappings({ @Mapping(target = "cliente", ignore = true) }) Compra toCompra(Purchase purchase); }
Cristian David Restrepo Marin
@Mapper(componentModel = "spring", uses = {ProductMapper.class}) public interface PurchaseItemMapper { @Mappings({ @Mapping(source = "id.idProducto", target = "productId"), @Mapping(source = "cantidad", target = "quantity"), @Mapping(source = "total", target = "total"), @Mapping(source = "estado", target = "active") }) PurchaseItem toPurchaseItem(ComprasProducto producto); @InheritInverseConfiguration @Mappings({ @Mapping(target = "compra", ignore = true), @Mapping(target = "producto", ignore = true), @Mapping(target = "id.idCompra", ignore = true) }) ComprasProducto toComprasProducto(PurchaseItem purchaseItem); }
CARLOS RODRIGO DEL TORO ORTIZ
Excelente todo hasta ahora
Alexandra Serna Cardona
¡Hola! ¿Los atributos que tienen el @JoinColumn deberían también tener los getters y los setters o hay algo en las buenas prácticas que indique que no es necesario?
Con respecto a MapStruct desde java 8 en adelante no es necesario usar la anotación @Mappings (No afecta si se usa):
Ejm: Pasamos de esto (CategoryMapper):
@Mappings({ @Mapping(source = "idCategoria", target = "categoryId"), @Mapping(source = "descripcion", target = "category"), @Mapping(source = "estado", target = "active") }) Category toCategory(Categoria categoria);
a esto:
@Mapping(source = "idCategoria", target = "categoryId") @Mapping(source = "descripcion", target = "category") @Mapping(source = "estado", target = "active") Category toCategory(Categoria categoria);
y no afecta su funcionamiento de las dos maneras funciona.
En la mayoría de los casos, devolver una lista vacía es suficiente y más claro que usar un Optional<List<T>>. Si encuentras que estás usando Optional para listas o colecciones, deberías reconsiderar si realmente es necesario o si devolver una colección vacía es más apropiado. El uso de Optional está más alineado con representar la ausencia de un valor único, no la ausencia de elementos en una colección.