2012-06-10 11 views
5

¿Cuál es exactamente la diferencia de las dos declaraciones siguientes- JPA diferencia en el uso de la propiedad mappedBy para definir la entidad propietaria

B es el lado propietario

@Entity 
class A { 
    @Id int id; 

    @OneToOne 
    B b; 
} 

@Entity 
class B { 
    @Id int id; 

    @OneToOne(mappedBy="b") 
    A a; 
} 

A es el lado propietario

@Entity 
class A { 
    @Id int id; 

    @OneToOne(mappedBy="a") 
    B b; 
} 

@Entity 
class B { 
    @Id int id; 

    @OneToOne 
    A a; 
} 

Pensando en esto en "SQL normal" creo que es lo mismo que tener dos tablas cada una con la clave externa de la otra tabla. Sin embargo, lo que no entiendo es cuál es el efecto de especificar qué entidad es propietaria, es decir, usar la propiedad 'mappedBy'. Lo que realmente logra esto, ya que no creo que haya un equivalente en SQL normal.

+2

¿Ha comprobado que en ambos casos las tablas A y B tendrán FK entre sí? –

Respuesta

10

El JPA 2.0 specification, sección 2.9, escribe:

relaciones pueden ser bidireccional o unidireccional. Una relación bidireccional tiene un lado propietario y un lado inverso (no propietario). Una relación unidireccional tiene solo un lado dueño. El lado propietario de una relación determina las actualizaciones de la relación en la base de datos, como se describe en la sección 3.2.4.

Las siguientes reglas se aplican a las relaciones bidireccionales:

  • El lado inverso de una relación bidireccional que referirse a su lado propietario por el uso del elemento mappedBy del OneToOne, OneToMany o ManyToMany anotación. El elemento mappedBy designa la propiedad o el campo en la entidad que es el propietario de la relación.
  • El lado de muchas de las relaciones bidireccionales de uno a muchos/varios a uno debe ser el lado propietario, por lo tanto, el elemento mappedBy no se puede especificar en la anotación ManyToOne.
  • Para las relaciones bidireccionales uno-a-uno, el lado propietario corresponde al lado que contiene la clave externa correspondiente.
  • Para relaciones bidireccionales de muchos a muchos, cada lado puede ser el lado propietario.

Las partes pertinentes de la sección 3.2.4 son:

El estado de entidades persistentes se sincroniza con la base de datos en confirmación de transacción. Esta sincronización implica escribir en la base de datos cualquier actualización a las entidades persistentes y sus relaciones como se especifica anteriormente.

y

relaciones bidireccionales entre entidades gestionadas se conservará en base a las referencias en poder de la parte propietaria de la relación. Es responsabilidad del desarrollador mantener las referencias en memoria retenidas en el lado propietario y las retenidas en el lado inverso coherentes entre sí cuando cambian. En el caso de las relaciones unidireccionales uno a uno y uno a muchos, es responsabilidad del desarrollador asegurarse de que se respete la semántica de las relaciones.

Es particularmente importante asegurarse de que los cambios en el lado inverso del resultado en relación actualizaciones correspondientes en el lado propietario, a fin de garantizar que los cambios no se pierden cuando se sincronizan con la base de datos.

+1

+1 para las referencias a la especificación. –

+0

Creo que esto concluye todas las otras respuestas :-) +1 – siebz0r

4

En el primer ejemplo de la mesa A va a tener 2 columnas id y b_id, la tabla B va a tener una columna, id. Esto hace que A sea el lado propietario.

En el segundo ejemplo B es el lado propietario. B tiene dos columnas, id y a_id. A va a tener una columna, id.

Y esa es la diferencia :-)

3

El lado propietario es el lado que considera APP saber es que existe la asociación o no. Supongamos que vas con tu primer ejemplo. El lado propietario es el lado donde no hay un atributo mappedBy. El lado propietario es, pues, A y B. No

Esto significa que si usted tiene una A y una B en la base de datos, y hacer

A a = em.find(A.class, aId); 
B b = em.find(B.class, bId); 
a.setB(b); 

APP salvará la asociación (es decir, se almacenará el ID de B en la columna de unión de la tabla A).

Pero si lo hace

A a = em.find(A.class, aId); 
B b = em.find(B.class, bId); 
b.setA(a); 

nada va a cambiar en la base de datos, ya que modificó el lado inverso y se olvidó de modificar el lado propietario.

6

Como otros han señalado, que están equivocados acerca de qué lado es el lado propietario en sus ejemplos. Con poseer un lado nos referimos a poseer la relación desde un OO perspecitve, en la práctica que a menudo termina siendo el opuesto de cómo se genera o se generará en el DB si se usa un rdbm como proveedor de persistencia.

En circunstancias normales, el modelo OO deja bastante claro qué lado es el que posee. Por ejemplo, un pedido tiene líneas de pedido. Si borramos un pedido, todas las líneas de pedido deben ser eliminadas. Si borramos una OrderLine, es posible que la orden aún tenga derecho a existir. Por lo tanto, la Orden es el lado dueño.

Para un ejemplo más concreto y excelente, sobre los efectos de qué lado está el lado propietario, me refiero a la respuesta de @JB Nizet.

Según la sección 2.9 de la JPA 2.0 spec:

Para uno-a-uno relaciones bidireccionales, el lado propietario corresponde al lado que contiene la clave externa correspondiente.

Pero en la misma sección también tenemos:

Además, esta especificación también requiere un apoyo para la siguientes estrategias de mapeo alternativas: [..] El mapeo de uno unidireccionales y bidireccionales relaciones de uno a uno, relaciones bidireccionales de muchos a uno/uno a muchos, y relaciones unidireccionales de varios a uno mediante el mapeo de tablas de unión .

Un poco futher abajo en la misma sección que sigue con:

anotaciones de mapeo adicionales (por ejemplo, columna y tabla de asignación anotaciones) se pueden manera especificada para anular o refinar el valor predeterminado además asignaciones y estrategias de mapeo descritas en la Sección 2.10. Algunas implementaciones hacen uso de eso para permitir que el FK de OneToOne bireccional esté en la tabla de destino.

leer algo sobre algunas estrategias para resolver ese escenario, ver: An almost good explaination

No he comprobado pero espero y creen que el 2,1 eliminará la primera cita. Dado que la estructura de la base de datos real debe poner el menor límite posible sobre cómo podemos modelar datos como entidades.

+0

No, JPA especifica que el lado propietario de una asociación bidireccional de OneToOne es el que contiene la clave externa. Lo mismo para OneToMany bidireccional. –

+0

"y se puede usar en una asignación de OneToOne en la que la clave principal de la entidad de referencia se utiliza como una clave externa para la entidad a la que se hace referencia". http://docs.oracle.com/javaee/6/api/javax/persistence/PrimaryKeyJoinColumn.html. La situación _just_ no aparece tan a menudo. – esej

+0

Y eso no cambia nada. En este caso, la columna de clave primaria es la columna de unión (de ahí el nombre PrimaryKeyJoinColumn), y la entidad que contiene esta anotación, y por lo tanto la columna de unión, es el lado propietario. La respuesta de Read @ meriton, que contiene este extracto de la especificación JPA: "Para las relaciones bidireccionales uno a uno, el lado propietario corresponde al lado que contiene la clave externa correspondiente". –

Cuestiones relacionadas