Leaky abstractions in JPA eclipselink


Leaky abstractions in JPA/Eclipselink
Leaky abstractions in JPA/EclipseLink

In our team we use JPA, EclipseLink to be precise. Now we start stress testing we notice something weird. The child relations of a entity are not updated if we only save the child. Probably we can prevent it by some configuration/annotation or other way, but we use an ORM to make sure we don’t have to think about these things.

Let me give you some code samples. There are two entities involved: ParentEntity and ChildEntity:

public class ParentEntity {
       
    private long id; 
   
    private List<ChildEntity> childs;

    @Id
    @SequenceGenerator ... 
    @Column ....   
    public long getId() {
        return this.id;
    }

    public void setId(long id) {
        this.id = id;
    }
    
    @OneToMany(mappedBy = "parent")
    @Column ....
    public List<ChildEntity> getChilds() {
        return this.childs;
    }

    public void setChilds(List<ChildEntity> childs) {
        this.childs = childs;
    }
} 
public class ChildEntity {
   
    private long id; 
   
    private ParentEntity parent;

    @Id
    @SequenceGenerator ... 
    @Column ....   
    public long getId() {
        return this.id;
    }

    public void setId(long id) {
        this.id = id;
    }

    @ManyToOne
    @JoinColumn ...
    public ParentEntity getParent(){
        return this.parent;
    }

    public void setParent(ParentEntity parent) {
        this.parent = parent
    }

} 

Furthermore we have a ParentEntityRepository object manages access to the entities.

public class ParentEntityRepository {
   
    @PersistenceContext  
    private EntityManager em;
    
    public ParentEntity save(ParentEntity parent) {    
        return em.merge(parent);
    }

    public ChildEntity saveChild(ChildEntity child) {
        return em.merge(child);    
    } 

    public List findParents() {
         return em.createQuery("select parent from ParentEntity parent").getResultList();
    } 

Some times we need to add a new child to an existing parent. The easiest way to do that is to create a child set the parent and save the child.

    ...
    @EJB
    ParentEntityRepository repos;
    
    public void addNewChildToParentAndProcess(ParentEntity parent) {
        ChildEntity child = new ChildEntity();
        child.setParent(parent);
        repos.saveChild(child);
      
        process();
    }

    public void process() {
        List parents = repos.findParents();  
        //display all parents including children
    }
    ...

The problem now is that the new child is not added to the parent in our front-end, but in the database the child is added and has the correct parent attached to it. After some time (EclipseLink cache expiration?) the results are correct.

I think this is really disturbing. You use a ORM to have an abstraction from your data layer, but it seams it’s a leaky one. I can’t remember that Hibernate has the same behavior, my memory might be misleading me though ;-).

P.S. The solution is to add the child to the parent and then save the parent, but I don’t think that should be the case.

Edit:
Coen Damen pointed me to the EclipseLink F.A.Q. with another solution by calling refresh() on the parent. Still I think it should be managed by the framework as I don’t want to think about database relations and when to refresh an entity.

,

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.