Existen ocasiones en donde se requieres marcar más de un campo como @Id, conformando con esto una llave primaría compuesta. En estos casos se requiere complementar la entidad con una clase adicional que será utilizada como ID y además tendrá que ser referenciada desde la clase donde se requiere una llave compuesta.
La utilización de @IdClass es una de las dos opciones para definir llaves primarias compuestas, y esta consiste en crear una clase adicional únicamente con los campos que corresponden a la llave primaria.
Veamos un caso concreto, normalmente un empleado puede tener más de un teléfono, entonces, podríamos crear una tabla donde la llave primaria sea el ID del empleado y el tipo de teléfono, de esta forma nos aseguramos de tener solo un tipo de teléfono por empleado. Veamos cómo quedaría la clase ID:
package com.obb.jpa.jpaturorial.entity.pk; import java.util.Objects; import javax.persistence.Id; /** * @author Oscar Blancarte */ public class TelephonePK { private Long employeId; private String telType; @Override public int hashCode() { int hash = 7; hash = 59 * hash + Objects.hashCode(this.employeId); hash = 59 * hash + Objects.hashCode(this.telType); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final TelephonePK other = (TelephonePK) obj; if (!Objects.equals(this.telType, other.telType)) { return false; } if (!Objects.equals(this.employeId, other.employeId)) { return false; } return true; } /** GET AND SET */ }
Definimos la clase TelephonePK, la cual solamente tiene como atributos el tipo de teléfono y el id del empleado. Observemos que esta no requiere de ningún tipo de anotación, pero si es requerido sobrescribir los métodos hashCode & equals.
La siguiente clase que definimos es la Entidad Telephone la cual representa un teléfono de empleado.
package com.obb.jpa.jpaturorial.entity; import com.obb.jpa.jpaturorial.entity.pk.TelephonePK; import java.util.Objects; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.IdClass; import javax.persistence.Table; /** * @author Oscar Blancarte */ @Entity @Table(name = "Telephones") @IdClass(value = TelephonePK.class) public class Telephone { @Id private Long employeId; @Id private String telType; private String number; /** GET, SET, HashCode & Equals */ }
Observemos que esta clase cuanta con el Id del empleado y el tipo de teléfono marcados como @Id, además, tiene la anotación @IdClass a nivel de clase y como valor tiene la clase EmployeePK.
Un dato importante es que tanto la definición de los atributos en la clase ID como en la clase Entidad deben de coincidir a la perfección en caso contrario provocara un error en tiempo de ejecución.
Tras aplicar estos últimos cambios la siguiente tabla será generada:
Observemos que la tabla contiene tanto los campos de la entidad Telephone como la clase id TelephonePK.
Tambíen los quiero invitar a ver mi curso de JPA, donde explico todos estos temas aplicados con API REST, https://codmind.com/courses/jpa
En lo particular, esté método para definir llaves primarías compuestas no me agrada mucho, debido a que me obliga a repetir los atributos en las dos clases. En la siguiente sección hablaremos del segundo método para implementar llaves compuestas utilizando la anotación @EmbeddedId.
NOTA: Este artículo es solo una sección del Tutorial de JPA, para ver el contenido completo de este tutorial regresa al Índice en el botón de abajo.
Excelente tutorial, muchas gracias.
Muchas gracias Ernesto
Como podria realizar lo que es una relacion de tablas de uno a cero-muchos, ya que he leido y JPA no me lo permite como tal, hay alguna manera??
La relación que necesitas es la Uno a Muchos, la cual puedes implementar con la anotación
@OneToMany
, puedes como implementarla en mi tutorial, te dejo la liga: https://www.oscarblancarteblog.com/2018/12/20/relaciones-onetomany/saludos.
Estimado… gracias por compartir esta información, en este momento de desarrollo me ha sido de mucha utilidad; no tenia idea de que se podía hacer esto en Spring boot. Podrías explicar la diferencia de usar @IdClass o @EmbededId, gracias
Hola Pedro, la diferencia tiene el mismo objetivo, solo que son difernetes formas de mapear los ID de las entidades que tiene Llaves compuestas, con IdClass lo que haces es definir las propiedades como parte de la clase, y con EmbedableId lo que haces es que delegas las propiedades a una clase aparte. En realidad es algo confuso de explicar con detalle por este medio, pero si te interesa, tengo un curso dedicado a JPA, por si quieres darle un vistazo: https://codmind.com/courses/jpa
Muchas gracias por el artículo, excelente tutorial.
Saludos Oscar.
Gracias por el comentario Salvador.