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

About these ads

3 Comments »

  1. Anonymous said

    It’s really not as bad as you make out… You simply have one method on the Parent object:

    addChild(Child child) {
    child.setParent(this);
    getChildren().add(child);
    }

    For removing a Manager, as you’ve discussed, you would similarly encapsulate this functionality in one method.

    What this buys you, and I think it’s a bargain, is the ability to test your domain model outside a container and use it disconnected from the database.

    Jason Carreira

  2. [...] But there is a catch! While container managed relationships (CMR) as defined by EJB 2.x made sure that adding an OrderLine object to the orderLines property of an Order also sets the order property on that OrderLine (and vice versa), JPA (being a POJO framework) performs no such magic. This is actually a good thing because it makes our domain objects usable outside of a JPA container, which means you can test them more easily and use them when they have not been persisted (yet). But it can also be confusing for people that were used to EJB 2.x CMR behaviour. [...]

  3. [...] But there is a catch! While container managed relationships (CMR) as defined by EJB 2.x made sure that adding an OrderLine object to the orderLines property of an Order also sets the order property on that OrderLine (and vice versa), JPA (being a POJO framework) performs no such magic. This is actually a good thing because it makes our domain objects usable outside of a JPA container, which means you can test them more easily and use them when they have not been persisted (yet). But it can also be confusing for people that were used to EJB 2.x CMR behaviour. [...]

RSS feed for comments on this post · TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: