Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate orphanRemoval removes all rows and then inserts rows

Following example is simplified.

I have following database structure:

X
 -xid VARCHAR

Y
 -yid VARCHAR
 -xid VARCHAR
 -zid VARCHAR
Z
 -zid VARCHAR

I have following Entity structure

@Entity
@Table(name = "X")
public class EntityX {
    @Id
    @Column(name = "xid")
    private String xid;

    @OneToMany(... mappedBy = "x", cascadeType.ALL, orphanRemoval=true)
    private List<EntityY> yList = new ArrayList();
    ...
}

@Entity
@Table(name = "Y")
public class EntityY {  
    @Id
    @Column(name = "yid")
    private String yid;

    @ManyToOne(cascadeType.ALL)
    private x;

    @ManyToOne(cascadeType.ALL)
    private z;
    ...
}

@Entity
@Table(name = "Z")
public class EntityZ {
    @Id
    @Column(name = "zid")
    private String zid;
}

My save method is:

X x = new X();
x.setXid(1);

Z z = new Z();
z.setZid(1);

Z z2 = new Z();
z2.setZid(2);

Y y = new Y();
y.setYid(1);
y.setX(x);
y.setZ(z);

Y y2 = new Y();
y2.setYid(2);
y2.setX(x);
y2.setZ(z2);

List<Y> yList = new ArrayList<Y>();
yList.add(y);
yList.add(y2);
x.setYList(yList);

entityManager.persist(x);

The save is working perfectly and sqls are:

insert into X (XID) values (1);
insert into Z (ZID) values (1);
insert into Y (YID, XID, ZID) values (1, 1, 1);
insert into Z (ZID) values (2);
insert into Y (YID, XID, ZID) values (2, 1, 2);

My update method is:

X x = new X();
x.setXid(1);

Z z = new Z();
z.setZid(1);

Z z3 = new Z();
z3.setZid(3);

Y y = new Y();
y.setYid(1);
y.setX(x);
y.setZ(z);

Y y3 = new Y();
y3.setYid(3);
y3.setX(x);
y3.setZ(z3);

List<Y> yList = new ArrayList<Y>();
yList.add(y);
yList.add(y3);
x.setYList(yList);

entityManager.merge(x);

The update does following sqls:

insert into Z (ZID) values (3);
insert into Y (YID, XID, ZID) values (3, 1, 3);

delete from Y where XID=1; Why?
delete from Z where XID=1; Why?
delete from Y where XID=2;
delete from Z where XID=2;

insert into Z (ZID) values (1); Why?
insert into Y (YID, XID, ZID) values (1, 1, 1); Why?

Why Y (YID=1) and Z (ZID=1) are deleted and after they are inserted? This is a performance problem if there are for example 100000 times Y and Z which are not changed.

like image 864
Sakke Avatar asked Dec 06 '25 18:12

Sakke


1 Answers

When you are trying to update, do not try to create the entity manually again and perform the merge. You end up having problems when you have cascading options set on your related entities like above.

During the merge, the persistence context retrieves the x(xid=1) entity along with the OneToMany list. You newly created X entity though has a new instance of list. Now persistence provider takes under consideration the orphanRemoval flag and decides that the previous state is not valid any removes all the content of Y with xid=1 (as they are not present in the new list).

Then it inserts the newly added elements in the new List.

I would recommend fetching the X with xid=1 first and then performing the update on a persistence-context managed entity:

X x = session.get(X.class, 1);
...

List<Y> yList = x.getYList();
yList.add(y);
yList.add(y3);

entityManager.merge(x);

all within one transactional method.

like image 126
Maciej Kowalski Avatar answered Dec 08 '25 08:12

Maciej Kowalski



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!