Archive for August, 2004

EJB Container-Managed vs POJO Relationships

When moving from EJB 2.x CMP Entity Beans to O/R Mapping Frameworks like Hibernate or Toplink you should be aware of the fundamentally different approaches in dealing with relationships between persistent objects. Today, I had a look at the book “Hibernate in Action“; on page 106 in chapter 3.7.1, the authors discuss “managed associations” and this is very interesting and important:

If you’ve used CMP 2.0/2.1, you’re familiar with the concept of a managed association(or managed relationship). CMP associations are called container-managed relationships (CMRs) for a reason. Associations in CMP are inherently bidirectional:

A change made to one side of an association is instantly reflected at the other side. For example, if we call bid.setItem(item), the containe automatically calls item.getBids().add(item).

Transparent POJO-oriented persistence implementations such as Hibernate do not implement managed associations. Contrary to CMR, Hibernate associations are all inherently unidirectional. As far as Hibernate is concerned, the association from Bid to Item is a different association than the association from Item to Bid.

To some people, this seems strange; to others, it feels completely natural. After all, associations at the Java language level are always unidirectional – and Hibernate claims to implement persistence for plain Java objects. We’ll merely observe that this decision was made because Hibernate objects, unlike entity beans, are not assumed to be always under the control of a container. In Hibernate applications, the behavior of a non-persistent instance is the same as the behavior of a persistent instance.

For an example consider a manager entity with a (bidirectional) 1:N relationship to employees that work for him. Additionally, a manager is associated with projects (N:M relationship), for some of them, he is even a teamleader (unidirectional relationship of teamleader entity). Now, a certain manager, for some reason, moves to another department and is disassociated with his employees and his current projects (and vice versa) and is teamleader no more.

With EJB 2.x CMP Entity Beans and their Container-Manager Relationships (CMR) this is one line of code:

// Implicitly removes manager from its employees and projects
// and also removes him as any teamleader
manager.remove();

That’s it! The Persistence Manager handles all the details, because he has to enforce referential integrity and knows the entity model/relationships from the deployment descriptor. What details? Well, look at how this is achieved with Toplink (same with Hibernate):

Iterator iterator = (Vector)manager.getEmployees().iterator();
while(iterator.hasNext()){
    employee = (Employee)iterator.next();
    // For bi-directional relationships,
    // it is important to maintain both sides
    // of the relationship when changing it:
    employee.setManager(null);
}
manager.setEmployees( new Vector() );

iterator = (Vector)employee.getProjects().iterator();
while(iterator.hasNext()){
    project = (Project)iterator.next();
    if(project.getTeamLeader() == manager){
        project.setTeamLeader(null);
    };
}
manager.setProjects( new Vector() );

unitOfWork.deleteObject(manager); 

Why I am mentioning this? Because EJB 2.x Container-Managed Relationships (CMR) are really easy to use, quite fool-proof. POJO persistence, on the other hand, requires a lot of involvement and understanding of the entity relationship model from you. Actually, you manually express the logic which is already expressed in the mapping descriptor in your source code, a somehow redundant work. I think this approach lacks scalability w.r.t. the model complexity and coding errors quickly lead to an inconsistent database (or to SQL exceptions in case of foreign key constraints).

Comments (3)