Pregunta

La especificación JPA (API de persistencia de Java) tiene 2 formas diferentes de especificar claves compuestas de entidad: @IdClass y @EmbeddedId .

Estoy usando ambas anotaciones en mis entidades asignadas, pero resulta ser un gran lío 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é?

¿Fue útil?

Solución

Considero que @EmbeddedId es probablemente más detallado porque con @IdClass no puede acceder a todo el objeto de clave primaria utilizando ningún operador de acceso de campo. Usando el @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 forman la clave compuesta porque todos están agregados 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, entendemos a partir de la consulta que un campo determinado es parte de la clave compuesta es de una ayuda inestimable.

Otros consejos

Descubrí una instancia en la que tenía 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 representa explícitamente las filas en la tabla de unión. No pude hacerlo funcionar de esta manera. Afortunadamente, "Java Persistence With Hibernate" tiene una sección dedicada a este tema. Una solución propuesta fue muy similar a la mía, pero en su lugar usó EmbeddedId. Modelé mis objetos según los del libro, ahora se comporta correctamente.

Hay tres estrategias para usar una clave principal compuesta:

  • Márquelo como @Embeddable y agregue a su clase de entidad una propiedad normal, marcada con @Id .
  • Agregue a su clase de entidad una propiedad normal para ella, marcada con @EmbeddedId .
  • Agregue propiedades a su clase de entidad para todos sus campos, márquelos con @Id y marque su clase de entidad con @IdClass , proporcionando la clase de su primaria clase clave.

El uso de @Id con una clase marcada como @Embeddable es el enfoque más natural. La etiqueta @Embeddable se puede usar para los valores de incrustación de clave no primaria de todos modos. Le permite tratar la clave principal compuesta como una propiedad única, 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 utilizar en otras tablas, ya que no es una entidad @Embeddable , pero sí 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 los Propiedades en la clase de clave primaria. Los nombres deben corresponder (no hay ningún 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 & # 8220; ocultar & # 8221; el uso de la clase de clave primaria desde la interfaz de la entidad envolvente. La anotación @IdClass toma un parámetro de valor de tipo de clase, que debe ser la clase que se utilizará como clave principal compuesta. Los campos que corresponden a las propiedades de la clase de clave principal que se utilizará deben anotarse con @Id .

Referencia: http://www.apress.com/us/book/9781430228509

Por lo que sé, si su PK compuesto contiene FK, es más fácil y más sencillo utilizar @IdClass

Con @EmbeddedId tiene que definir la asignación para su columna FK dos veces, una vez en @Embeddedable y una vez como, por ejemplo, @ManyToOne donde @ManyToOne tiene que ser de solo lectura ( @PrimaryKeyJoinColumn ) porque no puede tener una columna configurada en dos variables (posibles conflictos).
Por lo tanto, debe configurar su FK con un tipo simple en @Embeddedable .

En el otro sitio usando @IdClass esta situación puede manejarse mucho más fácilmente como se muestra en Claves primarias a través de OneToOne y ManyToOne Relationships :

Ejemplo de anotación de ID ManyToOne de JPA 2.0

...
@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 id 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;
    }
}

Creo que la principal ventaja es que podríamos usar @GeneratedValue para la ID cuando usamos @IdClass ? Estoy seguro de que no podemos usar @GeneratedValue para @EmbeddedId .

La clave compuesta no debe tener una propiedad @Id cuando se usa @EmbeddedId .

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 difícil lograr el mismo resultado con IdClass que deseará haga algo como FROM Entity WHERE idPartA =: idPartA0 AND idPartB =: idPartB0 .... O idPartA =: idPartAN AND idPartB =: idPartBN

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top