Creación de Entities con Clave Primaria Compuesta en JPA
Resumen
¿Cómo crear una entidad con clave primaria compuesta en JPA?
Al desarrollar aplicaciones, es común encontrarse con bases de datos que utilizan claves primarias compuestas. Esto ocurre cuando una tabla tiene más de una columna que, combinadas, forman su clave primaria única. JPA ofrece anotaciones específicas para manejar este tipo de estructuras dentro de nuestras aplicaciones. Descubrirás cómo implementar correctamente entidades con claves compuestas en Java, garantizando que tu modelo de datos sea robusto y fiel a la estructura de tu base de datos.
¿Qué son las claves primarias compuestas?
En una base de datos, una clave primaria es un conjunto de uno o más campos o columnas que identifican de manera única cada registro en una tabla. Las claves primarias compuestas se utilizan cuando más de una columna es necesaria para garantizar la unicidad de un registro.
Creación de una entidad Java con clave primaria compuesta
Primero, es esencial definir correctamente las clases y las anotaciones. A continuación, un proceso detallado para configurar una entidad en JPA cuando se enfrenta a una clave primaria compuesta:
@Entity@Table(name ="compras_productos")publicclassComprasProducto{@EmbeddedIdprivateComprasProductoPK id;privateint cantidad;privatedouble total;privateboolean estado;// Getters y Setters}
¿Cómo definir la clase de clave primaria compuesta?
Para representar la clave primaria compuesta, es necesario crear una clase adicional. Esta clase no es una entidad por sí misma, pero utiliza la anotación @Embeddable:
@EmbeddablepublicclassComprasProductoPKimplementsSerializable{@Column(name ="id_compra")privateint idCompra;@Column(name ="id_producto")privateint idProducto;// Getters y Setters}
Anotación @Embeddable: Indica que la clase puede ser incrustada en una entidad.
Implementación de Serializable: Requerida para que la clase pueda ser utilizada como clave primaria.
Implementación de la entidad con la clase Embedded
Dentro de la entidad principal, se debe utilizar la anotación @EmbeddedId:
@EmbeddedId: Se emplea cuando una clase contiene la clave primaria compuesta. Diferente de @Id, que se usaría para claves simples.
Este método garantiza que las columnas relevantes de la base de datos se vinculen correctamente a los atributos de la clase.
Principales atributos de la entidad
Además de manejar la clave primaria compuesta, la entidad debe incluir otros atributos que son íntegrales a la tabla:
Cantidad: Un entero que representa la cantidad de productos.
Total: Un tipo double que refleja el costo total de los productos. En bases de datos, se puede representar con tipos numéricos con precisión y escala.
Estado: Un booleano que indica si el registro está activo o no.
Creación de los métodos Getters y Setters
Es fundamental proporcionar métodos getters y setters para manipular las propiedades de las clases en Java, asegurando que se pueda acceder y modificar los valores conforme sea necesario.
Asegurando la integridad del modelo de datos
Finalmente, el siguiente paso en el desarrollo es establecer relaciones entre entidades para cumplir con el modelo de datos. Las relaciones, como @OneToMany, @ManyToOne, entre otras, configuran la manera en que las tablas interactúan entre sí, brindando un sistema coherente y robusto.
Con estos conocimientos, estarás bien equipado para manejar entidades con claves primarias compuestas en JPA, asegurando que tus aplicaciones se integren de manera efectiva con las bases de datos, respetando las reglas y restricciones del modelo de datos. Adelante, sigue explorando, aprendiendo y dominando estas herramientas para llevar tus habilidades de desarrollo al siguiente nivel. Aprende, experimenta y nunca dejes de expandir tus horizontes en el mundo del desarrollo.
Abro debate: Llaves compuestas es una mala practica si tienes campos adicionales en la tabla.
.
Si quieres relacionar muchos a muchos y tienes más campos adicionales para esa tabla, entonces se sugiere crear una PK única y te evitas mil pasos.
.
Si quieres relacionar muchos a muchos y no tienes mas campos adicionales que añadir, entonces haz la llave compuesta y haz una relación muchos a muchos.
Se puede simplemente hacer una tabla interfaz, aunque no tenga tributos extras mas que conectar las PK y FK de las tablas, te simplifica mucho el trabajo además de que es más entendible
Concuerdo con el comentario, para el ejemplo que es un diagrama pequeño está bien, pero ya para bases de datos relacional de muchas más tablas, se hace más difícil mantenerlo a largo plazo si es llave compuesta que si simplemente se genere una llave única, incluso si es para la tabla de la relación de muchos a muchos.
¿Por qué usamos tipos objetos como "Integer" y no su tipo primitivo "int"? ¿Se utilizarán posteriormente métodos de la clase "Integer"?
Se utilizan los tipos extendidos porque es posible que en un determinado momento tengamos un valor null desde la base de datos. Sí tuviéramos un "int" sería 0 por defecto y esto sería un error.
Muchas gracias
¿No es una mala practica tener una tabla con dos llaves primarias?
Cuando se usan tablas relacionales lo usual es que esta tabla tenga su propio id, eso es lo que tengo entendido de los cursos previos de SQL.
Tengo la misma duda, en cursos anteriores se decía que lo mejor era tener una llave primaria para una tabla intermedia en lugar de tener una clave compuesta.
Estaría bien aclarar esta duda.
no, antes asi quita la relacion de muchoa a muchos y siempre se crra una tabla intermedia ademas de quitar circularidad, en dicha tabla van la pk de cada una de las tablas en cuestion
Luego de colocar el implements Serializable, VSCode me marca un error y para resolverlo, el quick fix me sugiere que le agregue la línea:
private static final long serialVersionUID = 1L;
Podrías explicarnos por qué solicita esta línea?
Muchas gracias @soyalejoramirez
Muchas gracias
Las anotaciones de lombok funcionan para mapear objetos de la base de datos?
Puedes utilizar las anotaciones @Getter, @Setter, e incluso @Builder de Lombok para tu Entity.
Sin embargo, debes tener cuidado con otras anotaciones como @Data @ToString ó @EqualsAndHashCode ya que generan código que no es 100% correcto para entities (estas clases tienen algunos requerimientos especiales para estos métodos).
En este vídeo puedes ver a lo que me refiero y cómo evitarlo.
Utilizando @JoinColumn y @ManyToOne
Pero no hay que crear un List con anotacion @oneToMany en las clases de producto y compras o no es necesaio?
¿por qué ComprasProductoPK implementa Serializable y los demás entities no?
Solo los tipos que pueden ser embebidos necesitan implementar explícitamente la interface Serializable. Hibernate (la implementación de JPA que usa Spring Data) requiere que esto sea así cuando se usa luego con @Embeddable.
Esto debido que el id (el objeto completo) será usado como llave para indexar los objetos en la sesión y por lo tanto necesita estar serializado para no obtener un error de casteo.
Manera sencilla de implementar Setter y Getter
El código es mas limpio y fácil de leer
Toda la clase es como se ve en la imagen (Así de sencillo)
Y luego incluyen las anotaciones @Setter y Getter para generar los metodos
Perfecto, el reto anterior fue cumplido.
Muy bien
Para variables que representan dinero se debe de ocupar Bigdecimal en vez de Double
el MonetaryAmount tambien puede ser una posibilidad. Te invito a leer todo lo que viene en Java para el manejo de dinero en Java Money and Currency API.
implementsSerializable
tiene que ver con la serialización de objetos:
La serialización de un objeto consiste en generar una secuencia de bytes lista para su almacenamiento o transmisión. Después, mediante la deserialización, el estado original del objeto se puede reconstruir. Mas info aquí
alguien me puede explicar ese 'implements. Serializable'? gracias
¿Por que con mayúsculas los tipos? Tengo la costumbre de usar int, ¿cual es la diferencia?
Aparte de su valor por defecto, existe alguna otra diferencia?
no podemos usar los datos primitivos por que al trabajar con bases de datos podemos obtener NULL y en un int eso lo reconoceria como un 0 y eso ya es un error
Cual es la mejor forma de hacer este tipo de cosas, desde la clase "Compra" se pudo hacer una relacion de 1 a muchos con anotaciones y evitar crear otra clase o es mejor separarlo en otra clase aparte? Tengo esa duda
no seria mejor usar la anotacion ManyToMany para crear tablas compuestas?
Gracias
Encontraste la respuesta?
Hola profe, esta llave compuesta y lo que se hace acá representa la relación de muchos a muchos?
Para los que deseen aquí pueden encontrar mis notas hasta este momento en la sección de Spring y JPA
La aparición de import jakarta en lugar de import javax se debe a la evolución del ecosistema Java. A partir de Jakarta EE 9, las especificaciones de Java EE se transfirieron a la Fundación Eclipse, cambiando el paquete de javax a jakarta. Esto se realizó para facilitar la gestión y el desarrollo de la plataforma. Si estás utilizando una versión reciente de Spring o cualquier otra tecnología basada en Jakarta EE, es normal que veas esta nueva nomenclatura. Asegúrate de que tu proyecto esté correctamente configurado para trabajar con Jakarta EE.
Les recomiendo descargar la libreria Lombok para no escribir los setters y getters.
Solo basta con agregar la notación @Data y listo.
Para el constructor vacio y el que tiene argumenteos puedes utiizar: