java - not - primary key multiple jpa
Qué anotación debería usar: @IdClass o @EmbeddedId (7)
Con EmbeddedId puede usar la cláusula IN en HQL, por ejemplo: FROM Entity WHERE id IN :ids
donde id es un EmbeddedId, mientras que es doloroso lograr el mismo resultado con IdClass, querrá hacer algo como FROM Entity WHERE idPartA = :idPartA0 AND idPartB = :idPartB0 .... OR idPartA = :idPartAN AND idPartB = :idPartBN
La especificación JPA
(Java Persistence API) tiene 2 formas diferentes de especificar claves compuestas de entidad: @IdClass
y @EmbeddedId
.
Estoy utilizando ambas anotaciones en las entidades asignadas, pero resulta ser un gran desastre para las personas que no están muy familiarizadas con JPA
.
Quiero adoptar solo una forma de especificar claves compuestas. ¿Cuál es realmente el mejor? ¿Por qué?
Considero que @EmbeddedId
es probablemente más detallado porque con @IdClass
no se puede acceder a todo el objeto de la clave principal usando cualquier operador de acceso de campo. Usando @EmbeddedId
puedes hacer esto:
@Embeddable class EmployeeId { name, dataOfBirth }
@Entity class Employee {
@EmbeddedId EmployeeId employeeId;
...
}
Esto proporciona una noción clara de los campos que componen la clave compuesta porque todos se agregan en una clase a la que se accede a través de un operador de acceso de campo.
Otra diferencia con @IdClass
y @EmbeddedId
es cuando se trata de escribir HQL:
Con @IdClass
escribes:
select e.name from Employee e
y con @EmbeddedId
tienes que escribir:
select e.employeeId.name from Employee e
Tienes que escribir más texto para la misma consulta. Algunos pueden argumentar que esto difiere de un lenguaje más natural como el promovido por IdClass
. Pero la mayoría de las veces entender desde la consulta que un campo dado es parte de la clave compuesta es de una ayuda invaluable.
Creo que la principal ventaja es que podríamos usar @GeneratedValue
para el id cuando usamos @IdClass
? Estoy seguro de que no podemos usar @GeneratedValue
para @EmbeddedId
.
Descubrí una instancia en la que tuve que usar EmbeddedId en lugar de IdClass. En este escenario, hay una tabla de unión que tiene columnas adicionales definidas. Intenté resolver este problema utilizando IdClass para representar la clave de una entidad que explícitamente representa las filas en la tabla de unión. No podría hacerlo funcionar de esta manera. Afortunadamente, "Java Persistence With Hibernate" tiene una sección dedicada a este tema. Una solución propuesta era muy similar a la mía, pero en su lugar usaba EmbeddedId. Modelé mis objetos después de aquellos en el libro que ahora se comporta correctamente.
Hay tres estrategias para usar una clave primaria compuesta:
- Marque como
@Embeddable
y agregue a su clase de entidad una propiedad normal para él, marcada con@Id
. - Agregue a su clase de entidad una propiedad normal para él, marcada con
@EmbeddedId
. - Agregue propiedades a su clase de entidad para todos sus campos,
@Id
con@Id
y marque su clase de entidad con@IdClass
, suministrando la clase de su clase de clave primaria.
El uso de @Id
con una clase marcada como @Embeddable
es el enfoque más natural. La etiqueta @Embeddable
se puede usar de todos modos para valores no @Embeddable
clave primaria. Le permite tratar la clave primaria compuesta como una sola propiedad, y permite la reutilización de la clase @Embeddable
en otras tablas.
El siguiente enfoque más natural es el uso de la etiqueta @EmbeddedId
. Aquí, la clase de clave primaria no se puede usar en otras tablas, ya que no es una entidad @Embeddable
, pero nos permite tratar la clave como un atributo único de alguna clase.
Finalmente, el uso de las anotaciones @IdClass
y @Id
nos permite mapear la clase de clave primaria compuesta usando las propiedades de la entidad correspondiente a los nombres de las propiedades en la clase de clave primaria. Los nombres deben corresponderse (no existe un mecanismo para anular esto), y la clase de clave primaria debe cumplir las mismas obligaciones que con las otras dos técnicas. La única ventaja de este enfoque es su capacidad para "ocultar" el uso de la clase de clave primaria desde la interfaz de la entidad que lo contiene. La anotación @IdClass
toma un parámetro de valor del tipo Clase, que debe ser la clase que se utilizará como la clave primaria compuesta. Los campos que corresponden a las propiedades de la clase de clave primaria que se utilizarán se deben anotar con @Id
.
Referencia: http://www.apress.com/us/book/9781430228509
La clave compuesta no debe tener una propiedad @EmbeddedId
cuando se usa @EmbeddedId
.
Por lo que sé, si su PK compuesta contiene FK, es más fácil y más sencillo usar @IdClass
Con @EmbeddedId
tiene que definir la asignación para su columna FK dos veces, onece en @Embeddedable
y una vez para, por ejemplo, @ManyToOne
donde @ManyToOne
tiene que ser de solo lectura ( @PrimaryKeyJoinColumn
) porque no puede tener una columna establecida en dos variables (posibles conflictos).
Entonces debes establecer tu FK usando el tipo simple en @Embeddedable
.
En el otro sitio usando @IdClass
esta situación se puede manejar mucho más fácilmente como se muestra en las claves primarias a través de las relaciones OneToOne y ManyToOne :
Ejemplo de anotación de identificación de JPA 2.0 ManyToOne
...
@Entity
@IdClass(PhonePK.class)
public class Phone {
@Id
private String type;
@ManyToOne
@Id
@JoinColumn(name="OWNER_ID", referencedColumnName="EMP_ID")
private Employee owner;
...
}
Ejemplo de clase de identificación JPA 2.0
...
public class PhonePK {
private String type;
private long owner;
public PhonePK() {}
public PhonePK(String type, long owner) {
this.type = type;
this.owner = owner;
}
public boolean equals(Object object) {
if (object instanceof PhonePK) {
PhonePK pk = (PhonePK)object;
return type.equals(pk.type) && owner == pk.owner;
} else {
return false;
}
}
public int hashCode() {
return type.hashCode() + owner;
}
}