2009-10-07 9 views
11

Tengo dos entidades llamadas User y UserProfile en mi modelo de datos. Así es como están mapeados.Una pregunta sobre JPA Cascading

Código de entidad de usuario:

@OneToOne(cascade=CascadeType.ALL) 
@PrimaryKeyJoinColumn 
public UserProfile getUserProfile(){ 
    return this.userProfile; 
} 

public void setUserProfile(UserProfile userProfile){ 
    this.userProfile=userProfile; 
} 

Código de PerfilUsuario Entidad:

@OneToOne(mappedBy="userProfile",cascade=CascadeType.ALL) 
public User getUser(){ 
    return this.user; 
} 

public void setUser(User user){ 
    this.user=user; 
} 

Como se puede ver, tengo una CascadeType.ALL para el atributo de usuario en PerfilUsuario. Pero cuando intento eliminar la entidad UserProfile, la entidad User correspondiente permanece. (Cuando intento de eliminar la entidad de usuario, lo que corresponde PerfilUsuario entidad se elimina.)

Aquí es mi pregunta: -

  • interés cascadas ocupan sólo cuando especifico ellos en la entidad propietaria de la relación?
+2

su propia evidencia sugeriría que la respuesta es "sí" – skaffman

+0

@skaffman ..... Entonces, ¿es esta la única razón detrás del concepto de dueño y dueño? ¿O hay alguna otra? Gracias. – soontobeared

Respuesta

3

Como se ha dicho

Cuando intento de eliminar la entidad PerfilUsuario, la correspondiente entidad Usuario aún se mantiene

Tal vez cuando intenta quitar un PerfilUsuario se obtiene una violación de restricción de integridad de la base de datos: ¿utiliza el motor MyISAM en MySQL?

Pero como usted no dice nada al respecto. Tal vez su entidad UserProfile no tiene una referencia a una entidad de usuario.

Como se ha dicho en la especificación JPA

remove operación se conecta en cascada a entidades referenciados por X, si la relación de X a estas otras entidades se anota con la cascada = eliminar o cascada = ALL valor de elemento de anotación

Algo así como

UserProfile up = entityManager.find(UserProfile.class, id); 

entityManager.close(); 

// Notice User is null outside a persistence context 
// So user will be not removed from the database because UserProfile does not have a reference to it 
up.setUser(null); 

entityManager.getTransaction().begin(); 

entityManager.remove(up); 

entityManager.getTransaction().commit(); 

O usted tiene algo así como

entityManager.getTransaction().begin(); 

UserProfile up = entityManager.find(UserProfile.class, id); 

// throws UPDATE USER_PROFILE SET USER_ID = NULL 
up.setUser(null); 

// up.getUser() is null 
// So user is not removed 
entityManager.remove(up); 

entityManager.getTransaction().commit(); 

En respuesta al comentario de ChhsPly:

En Java Persistence con el libro de hibernación, vea el siguiente

El atributo cascada es direccional: Se aplica a sólo un extremo del la asociación.

creo que sería mejor que

Se aplica sólo a un extremo de la asociación por operación

Así que usted puede poner atributo cascada en ambos lados al mismo tiempo, incluso en una relación bidireccional. Entonces ChssPly tiene razón.

mappdePor atributo establece la relación bidireccional. El atributo mappedBy designó a la entidad Address como el lado inverso de la relación. Esto significa que la entidad Cliente es el lado propietario de la relación.

ChssPly tiene razón cuando dice mappedBy no tiene nada que ver con la cascada

+0

Eso es incorrecto. En primer lugar, 'mappedBy' no tiene nada que ver con la cascada: se usa para indicar el lado no propietario de la relación bidireccional. En segundo lugar, el atributo "cascada" es un ** atributo ** (como en "no una asociación") por lo que no es unidireccional o bidireccional en sí mismo. Se puede aplicar a asociación unidireccional o bidireccional (incluidos ambos lados simultáneamente). Ciertos ** tipos de cascada ** pueden no tener sentido en el lado de la asociación no propietaria. – ChssPly76

+0

Gracias, ChssPly. Como soy un hablante de inglés no nativo, tengo algunas limitaciones al escribir alguna respuesta. Agregado a la respuesta original. –

+0

@Arthur - gracias por sus ediciones (votaciones ascendentes); No quise ser duro o quisquilloso en la redacción, solo quería aclarar algunos puntos. El inglés no es mi primer idioma tampoco :-) – ChssPly76

1

Eso es correcto cuando se tiene una relación bidireccional dueño dicta las reglas en cascada, ya que es el "dueño". La entidad "de propiedad" básicamente sigue las órdenes, no puede dar las órdenes, por así decirlo.

15

Su pregunta es incorrecta en sí misma, que es de donde proviene toda la confusión. Arthur hizo un buen trabajo con su respuesta, pero está claro por los comentarios que la confusión aún persiste, así que déjame echar un vistazo aquí.

Haz cascadas ocupan sólo cuando especifico ellos en la entidad propietaria de la relación ?

"cascada" es un atributo que especifica en un (o posiblemente ambos en caso de bidireccional) final de una relación. Determina qué acciones realizó en que el extremo se propagará al otro extremo. Hay many different types de esas acciones definidas en JPA y even more definidas en las extensiones de Hibernate. Esta distinción es importante: solo debe hablar sobre comportamiento específico que se propaga y no "en cascada" en general.

PERSIST, MERGE, REFRESH se propagan normalmente (desde el final se declararon en el otro).

REMOVE, sin embargo, es complicado porque puede significar dos cosas diferentes. Si usted tiene una relación entre Un y B y que está tratando de eliminar Un, puede eliminar B en el otro extremo o puede quitar la asociación pero deje B intacta. Hibernate hace una clara distinción entre los dos; puede declarar los tipos de cascada REMOVE (DELETE) y DELETE_ORPHAN por separado; La especificación de JPA no. Tenga en cuenta que DELETE_ORPHAN no es compatible con relaciones de un solo valor (OneToOne/ManyToOne).

Por lo tanto, la propagación de REMOVE (por sí mismo o cuando es parte de ALL) depende de si la relación tiene un propietario claro (uni-direccional siempre hace; bi-direccional hace si se asigna usando mappedBy y no lo hace si es mapeado a través de join table) en cuyo caso se propaga desde el propietario al propietario O sin propietario, en cuyo caso se propaga en cualquier dirección pero sin semántica DELETE_ORPHAN a menos que se haya especificado explícitamente. Un ejemplo típico de este último es bidireccional de muchos a muchos.

+0

Hola Chss, lo he intentado aquí y funciona bien - OneToOne y ManyToMany. Aunque he usado Hibernate creo que funciona de la misma manera en JPA porque hibernate es un superconjunto de JPA. Creo que sería mejor si Soontobeared mostró el código donde intenta eliminar UserProfile y su entidad de usuario referenciada. Tal vez la aplicación arroje una violación de restricción y la entidad de usuario referenciada no se elimine. Nuevamente es difícil suponer qué sucedió. saludos, –

+0

... no. Hibernate es una IMPLEMENTACIÓN de JPA, esto no tiene nada que ver con un "superconjunto", eso ni siquiera tiene sentido – specializt

+1

Sería bueno si actualizas tu respuesta para reflejar el comportamiento huérfano actual de JPA 2. –

0

Con 2.x APP, si quieres una cascada quitar a continuación, utilizar orphanRemoval atributo:

@OneToMany(orphanRemoval=true)

documentación de verificación here para obtener más información.