2010-06-16 18 views
19

Quiero eliminar entidades huérfanas usando hibernación y JPA en una relación de muchos a muchos, pero todo lo que encontré fue este atributo, el atributo. org.hibernate.annotations.CascadeType.DELETE_ORPHAN (es decir, @Cascade (value = {org.hibernate.annotations.CascadeType.DELETE_ORPHAN)), que funciona solo para relaciones uno a muchos.¿Cómo elimino entidades huérfanas usando hibernación y JPA en una relación de muchos a muchos?

Quiero saber si puedo eliminar a los huérfanos en mi relación muchos a muchos.

Respuesta

-9

No utilice hibernate para eso, escriba código SQl y ejecútelo directamente en la base de datos de una manera establecida. Y luego arregle el problema estructural de la base de datos que le permitió obtener registros huérfanos en primer lugar. Es un signo de una base de datos muy mal diseñada si incluso tiene registros huérfanos. Este shouod será una solución de una vez, no algo que se ejecuta desde el código de la aplicación. Es una pena que no establezcas relaciones PK/FK adecuadas para empezar.

+0

No entendió el punto (como ya lo hizo cuando rechazó mi respuesta sobre el bloqueo optimista). –

+0

@Pascal Thivent: te perdiste el punto. Esto no es algo que deba hacerse NUNCA desde la interfaz de la aplicación. Este es un problema de base de datos y debe ser manejado por una base de datos correctamente diseñada. Y si abajo voté una de tus respuestas (que honestamente no sé si lo hice, no me suena), mencionar que en tu comentario cuando era irrelevante me parece que estás en una vendetta más que tratar de hacer lo correcto. – HLGEM

+0

Mi comentario es acerca del "problema estructural" imaginario al que también se refiere (no entendió el punto, insisto, el OP tiene PK/FK adecuado, simplemente no está pensando en el nivel del objeto).Entonces, lo creas o no, no rechacé tu respuesta anterior (no dudes en ponerte en contacto con un moderador de diamantes) incluso si creo que esta respuesta es irrelevante (como el voto negativo de [mi respuesta] (http://stackoverflow.com/). preguntas/2949039/concurency-problem-with-isolation-read-committed/2949534 # 2949534)). Así que no, no estoy en una vendetta (pero los comentarios se habrían apreciado). –

5

En realidad, hice una prueba con las siguientes entidades:

@Entity 
public class Person { 
    @Id 
    @GeneratedValue 
    private Long id; 
    private String firstName; 
    private String lastName; 

    @ManyToMany 
    @Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN) 
    private Set<Role> roles = new HashSet<Role>(); 

    //... 
} 

@Entity 
public class Role { 
    @Id 
    @GeneratedValue 
    private Long id; 

    private String name; 

    @ManyToMany(mappedBy = "roles") 
    private Set<Person> persons = new HashSet<Person>(); 

    //... 
} 

Y con el siguiente conjunto de datos:

<dataset> 
    <PERSON id="1" firstname="john" lastname="doe"/> 
    <PERSON id="2" firstname="clark" lastname="kent"/> 
    <PERSON id="3" firstname="james" lastname="bond"/> 
    <ROLE id="1" name="foo"/> 
    <ROLE id="2" name="bar"/> 
    <ROLE id="3" name="boo"/> 
    <ROLE id="4" name="baz"/> 
    <PERSON_ROLE persons_id="1" roles_id="1"/> 
    <PERSON_ROLE persons_id="1" roles_id="2"/> 
    <PERSON_ROLE persons_id="2" roles_id="2"/> 
    <PERSON_ROLE persons_id="2" roles_id="3"/> 
    <PERSON_ROLE persons_id="3" roles_id="1"/> 
    <PERSON_ROLE persons_id="3" roles_id="4"/> 
</dataset> 

El siguiente método de ensayo:

@Test 
public void testCascadeDeleteOrphanOnDelete() { 
    Person person = entityManager.find(Person.class, 1L); 
    entityManager.remove(person); 
    ReflectionAssert.assertPropertyLenientEquals("id", Arrays.asList(2, 3), findAllPersons()); 
    ReflectionAssert.assertPropertyLenientEquals("id", Arrays.asList(3, 4), findAllRoles()); 

} 

private List<Person> findAllPersons() { 
    return entityManager.createQuery("from Person").getResultList(); 
} 

private List<Role> findAllRoles() { 
    return entityManager.createQuery("from Role").getResultList(); 
} 

Sólo pasa. Por debajo de la salida producida:

 
Hibernate: select personx0_.id as id17_0_, personx0_.firstName as firstName17_0_, personx0_.lastName as lastName17_0_ from Person personx0_ where personx0_.id=? 
Hibernate: select roles0_.persons_id as persons1_1_, roles0_.roles_id as roles2_1_, rolex1_.id as id18_0_, rolex1_.name as name18_0_ from Person_Role roles0_ left outer join Role rolex1_ on roles0_.roles_id=rolex1_.id where roles0_.persons_id=? 
Hibernate: delete from Person_Role where persons_id=? 
Hibernate: delete from Role where id=? 
Hibernate: delete from Role where id=? 
Hibernate: delete from Person where id=? 
Hibernate: select personx0_.id as id17_, personx0_.firstName as firstName17_, personx0_.lastName as lastName17_ from Person personx0_ 
Hibernate: select rolex0_.id as id18_, rolex0_.name as name18_ from Role rolex0_ 
+1

¡Sí! He probado esto también. Realmente elimina todos los roles dependientes (en este caso) pero no puedo hacer eso. Necesito eliminar solo los huérfanos ... ¡Gracias por tu ayuda! – Alucard

+0

@ user368453: De hecho, es como Hibernate en cascada el DELETE (y entiendo ahora que esto no es lo que quieres). Me pregunto si Hibernate puede hacerlo mejor. –

+0

¡Sí! Ojalá pudiera ... pero parece que tendré que crear un disparador en la base de datos para hacer eso =/ – Alucard

-12

probar esto:

@ManyToMany(cascade = CascadeType.ALL, orphanRemoval=true, fetch = FetchType.LAZY, mappedBy = "yourObject") 
+0

Como dice el comentario a continuación, no hay tal atributo en ManyToMany-annotation. – cproinger

2

Hasta el momento no hay orphanRemoval atributo para la anotación ManyToMany. Yo también tengo el mismo problema. Y la sugerencia de implementarlo en la base de datos no es una respuesta al problema. Toda la filosofía de JPA es en contra de implementando la lógica en la base de datos, pero a través de las asignaciones.

7

Del libro "Pro APP 2":

Sólo las relaciones con cardinalidad simple en el lado de la fuente pueden permitir la extracción huérfano, por lo que la opción orphanRemoval se define en la @OneToOne y @OneToMany anotaciones de relación, pero en ninguna de las anotaciones @ManyToOne o @ManyToMany.

Es un fastidio, pero no hay eliminación huérfana automatizada JPA para ManyToMany.

Cuestiones relacionadas