versioning fails for onetomany collection holder
given parent entity
@Entity
public class Expenditure implements Serializable {
...
@OneToMany(mappe开发者_StackOverflow中文版dBy = "expenditure", cascade = CascadeType.ALL, orphanRemoval = true)
@OrderBy()
private List<ExpenditurePeriod> periods = new ArrayList<ExpenditurePeriod>();
@Version
private Integer version = 0;
...
}
and child one
@Entity
public class ExpenditurePeriod implements Serializable {
...
@ManyToOne
@JoinColumn(name="expenditure_id", nullable = false)
private Expenditure expenditure;
...
}
While updating both parent and child in one transaction, org.hibernate.StaleObjectStateException is thrown: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect):
Indeed, hibernate issues two sql updates: one changing parent properties and another changing child properties. Do you know a way to get rid of parent update changing child? The update results both in inefficiency and false positive for optimistic lock. Note, that both child and parent save their state in DB correctly.
Hibernate version is 3.5.1-Final
(...) Indeed, hibernate issues two sql updates: one changing parent properties and another changing child properties.
If you updated both parent and child in one transaction, isn't this the expected result?
Do you know a way to get rid of parent update changing child? The update results both in inefficiency and false positive for optimistic lock.
I don't understand the problem and couldn't reproduce it. The following test method (that runs inside a transaction) works for me (and it generates two updates as expected since I modified both the parent and one child).
@Test
public void testUpdate() {
Expenditure expenditure = new Expenditure();
ExpenditurePeriod expenditurePeriod1 = new ExpenditurePeriod();
ExpenditurePeriod expenditurePeriod2 = new ExpenditurePeriod();
expenditure.getPeriods().add(expenditurePeriod1);
expenditure.getPeriods().add(expenditurePeriod2);
expenditurePeriod1.setExpenditure(expenditure);
expenditurePeriod2.setExpenditure(expenditure);
em.persist(expenditure);
em.flush();
assertNotNull(expenditure.getId());
assertNotNull(expenditurePeriod1.getId());
assertNotNull(expenditurePeriod2.getId());
assertEquals(Integer.valueOf(0), expenditure.getVersion());
assertEquals(Integer.valueOf(0), expenditurePeriod1.getVersion());
assertEquals(Integer.valueOf(0), expenditurePeriod2.getVersion());
expenditure.setProperty("a");
expenditurePeriod1.setProperty("b");
em.merge(expenditure);
em.flush();
assertEquals(Integer.valueOf(1), expenditure.getVersion());
assertEquals(Integer.valueOf(1), expenditurePeriod1.getVersion());
assertEquals(Integer.valueOf(0), expenditurePeriod2.getVersion());
}
If this is not representative of your situation, please clarify.
精彩评论