users@glassfish.java.net

ManyToOne/OneToMany bidirectional relatioship gotcha

From: <glassfish_at_javadesktop.org>
Date: Thu, 29 Jan 2009 03:10:12 PST

I think it'll be better to explain the issue with an example:

Here we have a typical OneToMany bidirectional relationship
between to entities,...
[i]
@Entity()
public class ParentBean implements Serializable {
  private Set<ChildBean> childs = new HashSet<ChildBean>();
  
  @OneToMany(cascade = CascadeType.ALL, mappedBy="parent")
  public Set<ChildBean> getChilds() {
    return this.childs;
  }
}

@Entity()
public class ChildBean implements Serializable {
  private ParentBean parent;

  @ManyToOne ()
  public ParentBean getParent() {
    return this.parent;
  }
}
[/i]

...and the session bean facade which enable us to add a child
to a parent:
[i]
@Stateless
public class ExampleSessionFacadeBean implements... {

        ...

  public void addChild(ParentBean _parent, ChildBean _child) {

     //Attach the parent bean
     ParentBean parent = em.find(ParentBean.class,_parent.getId());
     //IMPORTANT: remember to update both sides of the relationship...
     //...inverse side
     parent.getChilds().add(_child); <------ (*)
     //...owning side
     child.setParent(parent);
     //Persist the entity
     em.persist(child);
  }

}
[/i]

The problem is with the line marked as (*); We all know the need to update both
sides of the relationship, but the catch is inside the 'add', because it causes
the load of the ENTIRE collection. When you have 100, perhaps 1000 childs, it's
barely noticeable, but when the number of child grows (in our application we could
have 1000000 or more childs), two related problems will arise:
 - Performance
 - Possible out of memory exception

I like to deploy bidirectional relatioships between my entities, because follows
server cleaner and easier code (parent.getChild() vs SELECT...), but basically because we've got cascade remove just setting the CASCADE attribute. But the issue exposed here clearly limits it's use, and drives you to the implementation of unidirectional ManyToOne relationships.

All this leads me to the following: "Use ManyToOne/OneToMany bidirectional relatioship only when the number of childs in the corresponding collection is small and controlled (the number is not going to grow as time goes by)"

Do you agree with me?, Am I missing something?

Thanks for your time!
[Message sent by forum member 'abelmj' (abelmj)]

http://forums.java.net/jive/thread.jspa?messageID=328900