2012-11-05 6 views
6

Moje pytanie jest dość podobna do tej jednej Hibernate Bi-Directional ManyToMany Updates with Second Level cacheHibernate Bi-Directional wiele do wielu stowarzyszenia tworzy duplikaty

mam klasę, jak pokazano poniżej

@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL) 
@Entity 
public class A{ 
    private int id; 
    private List<B> listB; 

    ... 
    @Cache (usage = CacheConcurrencyStrategy.TRANSACTIONAL) 
    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, targetEntity = B.class) 
    @JoinTable(name = "A_B", joinColumns = { @JoinColumn(name = "a_id") }, 
     inverseJoinColumns = { @JoinColumn(name = "b_id") }) 
    public List<B> getListB() { 
     return listB ; 
    } 
} 

@Cache (usage = CacheConcurrencyStrategy.TRANSACTIONAL) 
@Entity 
public class B{ 
    private int id; 
    private List<A> listA; 

    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, targetEntity = A.class) 
    @JoinTable(name = "A_B", joinColumns = { @JoinColumn(name = "b_id") }, inverseJoinColumns = { @JoinColumn(name = "a_id") }) 
    public List<a> getListA() { 
     return listA ; 
    } 

    public void addToA(A a) { 
     a.getListB().add(this); 
    } 
} 

Zgodnie z oczekiwaniami w wiele do wielu relacji, ja aktualizowałem obie strony dwukierunkowej relacji.

Problemem, przed którym stoję, są wyskakujące wyskakujące wpisy, gdy próbuję dodać/zaktualizować element w kolekcji. Poniżej znajduje się kod używam utrzymują jednostkę ...

b.getA().clear() ; 
... 
... 
b.getListA().add(A) ; 
b.addToA(A) ; 
em.saveOrUpdate(b) ; 

są następujące zapytania wystrzelone przez Hibernate, które są uzyskiwane z dzienników.

delete from A_B where b_id=? 

insert into A_B (b_id, a_id) values (?, ?) 
insert into A_B (b_id, a_id) values (?, ?) 

delete from A_B where a_id=? 

insert into A_B (a_id, b_id) values (?, ?) 
insert into A_B (a_id, b_id) values (?, ?) 
insert into A_B (a_id, b_id) values (?, ?) 
insert into A_B (a_id, b_id) values (?, ?) 

Gdzie ja się tu mylę? Jak pozbyć się duplikatów, które są wstawiane? Pamięć podręczna jest prawidłowo przepłukiwana, ale zduplikowane wpisy są jedynym problemem!

Odpowiedz

10

To jest klasyk!

Problem polega na tym, że oba twoje odwzorowania są właścicielami, gdy należy się ich właścicielem, i należy się odwrócić. Ponieważ oba są właścicielami, zmiany na którekolwiek z nich spowodują wstawienia do bazy danych; z jednym właścicielem i jednym odwrotnym, będzie tylko jeden zestaw wstawień.

Powinieneś być w stanie przepisać B::getListA jak:

@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, mappedBy = "listB") 
public List<A> getListA() 

I mieć wszystko działa.

Należy pamiętać, że tylko strona własna to adnotacja @JoinTable. Zasadniczo dowolny bit bazy danych jest mapowany w dokładnie w jednym miejscu w aplikacji JPA. Jeśli kiedykolwiek zauważysz, że coś odwzorowujesz dwa razy, sprawdź, czy jest lepszy sposób, aby to zrobić.

Nawiasem mówiąc, nie potrzebujesz atrybutów targetEntity; dostawca JPA może to rozwiązać na podstawie generycznych.

+3

Świetnie! Tak więc z atrybutem mappedBy informujemy Hibernate, aby powiadomić, która jest tabelą właściciela i konfiguracją łączenia encji. Czy moje zrozumienie jest poprawne? – Venkat

+2

Tak, właśnie to. –

+0

Czy wiesz, dlaczego możesz nadal otrzymywać powielone wstawki, gdy poprawnie skonfigurujesz mapowanie? W moim przypadku używam dostępu do pola zamiast dostępu do metody. Czy to może być problem? – JBCP

Powiązane problemy