2011-08-25 33 views
8

Estoy asking and answering my own question, pero no estoy suponiendo que tengo la mejor respuesta. Si tienes uno mejor, ¡por favor publícalo!Cómo crear una clave primaria compuesta que contiene un atributo @ManyToOne como @EmbeddedId en JPA?

preguntas relacionadas:

Tengo un par de clases que están en una relación simple agregación (?): Cualquier instancia de uno posee algunas instancias del otro. La clase propietaria tiene algún tipo de clave principal propia, y la clase poseída tiene un muchos a uno para esta clase a través de una clave externa correspondiente. Me gustaría que la clase poseída tenga una clave principal que comprenda esa clave externa más cierta información adicional.

En aras de la discusión, usemos esos favoritos perennes, Order y OrderLine.

El SQL es como la siguiente:

-- 'order' may have been a poor choice of name, given that it's an SQL keyword! 
create table Order_ (
    orderId integer primary key 
); 
create table OrderLine (
    orderId integer not null references Order_, 
    lineNo integer not null, 
    primary key (orderId, lineNo) 
); 

me gustaría mapear esto en Java utilizando JPA. El orden es trivial, y OrderLine puede manejarse con @IdClass. Here's the code for that - el código es bastante convencional, y espero que perdone mi idiosincrasia.

Sin embargo, usar @IdClass implica escribir una clase de ID que duplica los campos en OrderLine. Me gustaría evitar esa duplicación, así que me gustaría usar @EmbeddedId en su lugar.

Sin embargo, un ingenuo intento de hacer esto falla:

@Embeddable 
public class OrderLineKey { 
    @ManyToOne 
    private Order order; 
    private int lineNo; 
} 

OpenJPA rechaza el uso de eso como una @EmbeddedId. No he probado con otros proveedores, pero no esperaba que tuvieran éxito, porque la especificación JPA requiere que los campos que componen una clase de ID sean básicos, no relaciones.

Entonces, ¿qué puedo hacer? ¿Cómo puedo escribir una clase cuya clave contenga la relación @ManyToOne, pero se maneja como @EmbeddedId?

Respuesta

16

No sé de una manera de hacer esto que no implique la duplicación de ningún campo (lo siento!). Pero se puede hacer de una manera directa y estándar que implica la duplicación solo de los campos de relación. La clave es la @MapsId anotación introducida en JPA 2.

la clase de clave integrable se ve así:

@Embeddable 
public class OrderLineKey { 
    private int orderId; 
    private int lineNo; 
} 

Y la clase de entidad incrustación se ve así:

@Entity 
public class OrderLine{ 
    @EmbeddedId 
    private OrderLineKey id; 

    @ManyToOne 
    @MapsId("orderId") 
    private Order order; 
} 

La anotación @MapsId declara que el campo de relación al que se aplica efectúa un nuevo mapa de un campo básico del ID incrustado.

Here's the code for OrderId.

+9

¿Qué sucede si la entidad a la que se quiere referir tiene una clave compuesta?¿Puedes usar MapsId en múltiples columnas en la ID incrustada? –

Cuestiones relacionadas