2010-06-16 15 views
19

Voglio eliminare le entità orfane usando Hibernate e JPA su una relazione molti-a-molti, ma tutto ciò che ho trovato era questo attributo l'attributo. org.hibernate.annotations.CascadeType.DELETE_ORPHAN (ovvero @Cascade (value = {org.hibernate.annotations.CascadeType.DELETE_ORPHAN)), che funziona solo per le relazioni uno-a-molti.Come si eliminano le entità orfane usando Hibernate e JPA su una relazione molti-a-molti?

Voglio sapere se riesco a cancellare quelli orfani sulla mia relazione molti-a-molti.

risposta

-9

Non utilizzare la modalità di sospensione, scrivere il codice SQl ed eseguirlo direttamente sul database in modo set-based. Quindi correggere il problema strutturale del database che consente di ottenere i record orfani in primo luogo. È un segno di un database mal progettato se si dispone anche di record orfani. Questo shouod essere una correzione di un tempo non qualcosa che viene eseguito dal codice dell'applicazione. Vergognatevi per non aver impostato le relazioni PK/FK appropriate per cominciare.

+0

Hai perso completamente il punto (come hai già fatto quando hai ridiscusso la mia risposta sul blocco ottimistico). –

+0

@Pascal Thivent - ti sei perso il punto. Questo non è qualcosa che dovrebbe essere fatto SEMPRE dall'interfaccia dell'applicazione. Questo è un problema di database e dovrebbe essere gestito da un database progettato correttamente. E se scendessi ho votato una delle tue risposte (che sinceramente non so se l'ho fatto, non ha suonato un campanello), quindi accennando al fatto che nel tuo commento quando era irrilevante mi sembra che tu sia su una vendetta di più che cercare di fare la cosa giusta. – HLGEM

+0

Il mio commento riguarda l'immaginario "problema strutturale" a cui ti riferisci anche tu (hai perso il punto, insisto, l'OP ha il corretto PK/FK, non stai pensando al livello dell'oggetto).Poi, che ci crediate o no, non ho minimizzato la vostra risposta di cui sopra (sentitevi liberi di contattare un moderatore di diamanti) anche se penso che questa risposta sia irrilevante (come il downvote su [la mia risposta] (http://stackoverflow.com/ domande/2949039/concurency-problema-con-isolamento-read-committed/2.949.534 # 2.949.534)). Quindi no, non sono su una vendetta (ma il feedback sarebbe stato apprezzato). –

5

In realtà, ho fatto una prova con i seguenti soggetti:

@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>(); 

    //... 
} 

E con il seguente set di dati:

<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> 

Il seguente metodo:

@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(); 
} 

passa solo. Sotto l'output prodotto:

 
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ì! Ho provato anche questo. Elimina veramente tutti i ruoli secondari (in questo caso) ma non posso farlo. Devo cancellare solo quelli orfani ... Grazie per il tuo aiuto! – Alucard

+0

@ user368453: In effetti, è come se Hibernate fosse in cascata su DELETE (e ora capisco che questo non è quello che vuoi). Mi chiedo se Hibernate possa fare di meglio. –

+0

Sì! Vorrei che potesse ... ma sembra che dovrò creare un trigger sul database per farlo =/ – Alucard

-12

provare questo:

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

come commento qui sotto dice, non c'è un tale attributo sull'annotazione ManyToMany. – cproinger

2

finora non v'è alcuna orphanRemoval attributo per l'annotazione ManyToMany. Ho lo stesso problema anche io. E il suggerimento di implementarlo sul database non è una risposta al problema. L'intera filosofia di JPA è rispetto a che implementa la logica sul database, ma attraverso i mapping.

7

Dal libro "Pro JPA 2":

Solo rapporti con cardinalità singola sul lato sorgente possono consentire la rimozione orfano, che è il motivo per cui l'opzione è orphanRemoval definita sulla @OneToOne e @OneToMany annotazioni sulle relazioni, ma su nessuna delle annotazioni @ManyToOne o @ManyToMany.

È un fiasco, ma non è disponibile alcuna rimozione orfana automatizzata JPA per ManyToMany.

Problemi correlati