views:

38

answers:

1

given parent entity

@Entity
public class Expenditure implements Serializable {
...
    @OneToMany(mappedBy = "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

+1  A: 

(...) 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.

Pascal Thivent
Sorry, there are two _parent_ updates for me. One when updating parent and another one updating child. Will look into the test case and put result below.
Alexander Vasiljev
My first attempt to create a test that emulates broken versioning did not succeed. I'd make further attempts to see whether this is really Spring-specific or perhaps naturalId-specific issue.
Alexander Vasiljev