Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate trying to persist same object twice

I have 3 classes corresponding to 3 tables V, D and P. D had a FK to V (FK_V) and is join using OneToMany relationship. Also their exits a 4th table V_D_P which has the relationship of these V, D and P.

Following is what the data model for these looks like:

@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.
}

Now I want to persist V, D and P along with their relationship. I am

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

Now you can see the I am adding the same d object twice. Once to P and once to V_D_P. However since these are the same objects, only once of them should persist. However based on the hibernate logs I see that hibernate is trying to insert 2 different objects.

I also see the following exception: ORA-00001: unique constraint

Is there a way to let hibernate that these are the same objects and to persis them only once ?

like image 282
Suraj Menon Avatar asked Aug 06 '15 09:08

Suraj Menon


3 Answers

Objects are uniquely identified by id. Therefore they have to have the same id.

  • Either provide the id before,
  • or persist once and refresh d object before saving the other (so it has the id set).
like image 101
darijan Avatar answered Nov 17 '22 19:11

darijan


Try save() instead of persist(). As noted in this post, persist doesn't necessarily update the ID of the object immediately. That means that hibernate may encounter your 'd' object twice as is traverses the object graph. Both times it might say "the id is null, I need to insert a new one!".

Apparently this behavior isn't well defined, so it may not happen in all cases.

like image 29
T.D. Smith Avatar answered Nov 17 '22 20:11

T.D. Smith


Do you really need the VDP.d field: can't you just use a bi-directional (mapped) relation between V and V(D)P (V(D)P would have a v field) and just navigate V(D)P.v.d?

like image 1
Xavier Dury Avatar answered Nov 17 '22 19:11

Xavier Dury