2015-08-06 11 views
11

Mam 3 klasy odpowiadające 3 tabelom V, D i P. D miał FK do V (FK_V) i łączy się za pomocą OneToMany relacji. Również ich wyjścia 4 tabeli V_D_P, który ma związek z tych V, D i P.Hibernate próbuje przetrwać ten sam obiekt dwukrotnie

obserwuję to co model danych dla tych wygląda następująco:

@Entity 
@Table(name = "V")             
public class V { 

    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE) 
    @Column(name = "ID") 
    private Long id; 

    @OneToMany(cascade=CascadeType.ALL) 
    @JoinColumn(name = "FK_V", referencedColumnName="Id", nullable = false) 
    private Set<D> d; 

    @OneToMany(cascade=CascadeType.ALL) 
    @JoinColumn(name = "FK_V", referencedColumnName="Id", nullable = false) 
    private Set<V_D_P> vdp; 

    //Getters Setters etc. 
} 


@Entity 
@Table(name = "V_D_P") 
public class V_D_P { 

     @Id 
     @GeneratedValue(strategy = GenerationType.SEQUENCE) 
     @Column(name = "ID") 
     private Long id; 

    @ManyToOne(cascade=CascadeType.ALL) 
    @JoinColumn(name = "FK_D", nullable = false) 
    private D d; 

    @ManyToOne(cascade=CascadeType.ALL) 
    @JoinColumn(name = "FK_P", nullable = false) 
    private P p; 

    //Getters Setters etc.  
} 

@Entity 
@Table(name = "D")             
public class D { 
     @Id 
     @GeneratedValue(strategy = GenerationType.SEQUENCE) 
     @Column(name = "ID") 
     private Long id; 

    //Getters Setters etc. 
} 

@Entity 
@Table(name = "P")             
public class P { 

     @Id 
     @GeneratedValue(strategy = GenerationType.SEQUENCE) 
     @Column(name = "ID") 
     private Long id; 

    //Getters Setters etc. 
} 

Teraz chcę utrzymywać V, D i P wraz z ich relacji. Jestem

V v = new V(); 

D d = new D(); 
Set<D> dSet = new HashSet<>(); 
dSet.add(d); 
v.setD(dSet); // Adding d to V ....(1) 

P p = new P(); 
V_D_P vdp = new V_D_P(); 

vdp.setD(d); // Adding d to V_D_P ....(2) 
vdp.setP(p); 

Set<V_D_P> vdpSet = new HashSet<V_D_P>(); 
vdpSet.add(vdp); 
v.setVdp(vdpSet); 

entityManager.persist(v); 

Teraz widać dodaję ten sam d obiekt dwukrotnie. Raz do P i raz do V_D_P. Ponieważ jednak są to te same obiekty, tylko jeden z nich powinien się utrzymywać. Jednak na podstawie logów hibernacji widzę, że hibernacja próbuje wstawić 2 różne obiekty.

widzę też następujący wyjątek: ORA-00001 : unique

Czy istnieje sposób, aby pozwolić hibernacji, że są to te same przedmioty i Persis je tylko raz?

+1

Nie mogę odtworzyć Twojego problemu; generowana jest tylko jedna instrukcja wstawiania dla 'D'. Czy wszystkie adnotacje pochodzą z pakietu 'javax.persistence. *'? –

+1

@DraganBozanovic: Tak. Obie te adnotacje pochodzą z pakietu javax.persistence. *. Czy możesz potwierdzić, że dodajesz ten sam obiekt dwukrotnie (jak dSet.add (d); & vdp.setD (d);), a następnie próbujesz zachować oba? –

+1

Tak, skopiowałem wklejony kod. [Tutaj] (http://pastie.org/10341717) to wygenerowany przez Hibernate SQL; Próbowałem go z bazą danych H2 ('org.hibernate.dialect.H2Dialect'). Jakiego dialektu używasz i czy możesz wstawić SQL wygenerowany przez Hibernate w twoim przypadku? –

Odpowiedz

4

Obiekty są jednoznacznie identyfikowane za pomocą id. Dlatego muszą mieć ten sam identyfikator.

  • Albo podać identyfikator przed,
  • lub utrzymują raz odświeżyć d obiektu przed zapisaniem drugiego (tak to ma Set ID).
1

Wypróbuj save() zamiast persist(). Jak odnotowano w this post, persist nie musi natychmiast aktualizować ID obiektu. Oznacza to, że hibernacja może napotkać obiekt "d" dwukrotnie, tak jak przechodzi przez wykres obiektu. Za każdym razem może powiedzieć "id jest zerowy, muszę wstawić nowy!".

Podobno to zachowanie nie jest dobrze zdefiniowane, więc może nie zdarzyć się we wszystkich przypadkach.

1

Czy naprawdę potrzebujesz pola VDP.d: nie możesz użyć dwukierunkowej (odwzorowanej) relacji między V i V (D) P (V (D) P miałoby pole av) i po prostu nawiguj V (D) Pvd?