Search code examples
jpaeclipselinkentitylisteners

EclipseLink PreUpdate on OneToOne Relationship not persisted


I have a PreUpdate method which gets executed, but when flushing the entityManager the changes on the dependent entity are not persisted.

Following is my minimal (non) working example:

Entities

@Entity
@Table(name = "HOUSE")
public class House {

    @Id
    @Column(name = "ID")
    private long id;

    @OneToOne(cascade = {CascadeType.ALL})
    @JoinColumn(name = "INFO_ID")
    private HouseInfo info;

    @PreUpdate
    protected void komplettiereEingabeWerte() {
        info.setCode("TEST");
    }

    //getters and setters
}

@Entity
@Table(name = "HOUSE_INFO")
public class HouseInfo {

    @Id
    @Column(name = "ID")
    private long id;

    @Column(name = "CODE")
    private String code;

    //getters and setters
}

Testcase

@Test
@Transactional(TransactionMode.ROLLBACK)
public void testPreUpdate() {
    House house = entityManager.find(House.class, 1L);
    house.setInfo(new HouseInfo());
    entityManager.flush();
    entityManager.clear();

    house = entityManager.find(House.class, 1L);
    assertEquals("TEST", house.getInfo().getCode());
}

The Test fails due to an AssertionError on the last line as Code is null.

I am using EclipseLink version 2.7.4 with an Oracle DB (the same behaviour was also observed with an in memory Derby DB) and the Test is running with UnitilsJUnit4 in a SpringApplicationContext.

How can I fix this problem? Thank you.


Solution

  • The JPA Spec states that:

    In general, the lifecycle method of a portable application should not invoke EntityManager or query operations, access other entity instances, or modify relationships within the same persistence context. A lifecycle callback method may modify the non-relationship state of the entity on which it is invoked

    The simple answer is, then, that entity listeners cannot be used for the task. Implement the relevant logic in your service layer instead.