ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

EJB Inheritance, Part 2
Pages: 1, 2, 3

One-Table Mapping

As its name indicates, one-table mapping involves a single table, including rows belonging to all classes of the hierarchy. This single table must then have a special column to specify what kind of object is being stored in the rows. This column can bear many names: category, type, kind, class, variety, brand, sort, etc.

Here's the database schema for our RTM database.

Figure 3. One-table mapping database schema

We've introduced the Category field here, which can hold one of three values: "B" (base customer), "G" (Gold customer), and "P" (Platinum Customer). This field is pretty much useless in our business logic, but we still need to declare it to code the queries, as we'll see shortly. Don't forget to initialize this field in ejbCreate(), for the base class and all subclasses. The BaseCustomerBean class sets the field to "B," the GoldCustomerBean class sets the field to "G," and the PlatinumCustomerBean class sets the field to "P."

In this kind of table mapping, a single table contains all fields of all objects in the whole hierarchy. Fields that are not used in a certain row are simply left null. For example, the Charity field is not used by base and gold customers. This technique does produce a lot of null fields, but it shouldn't be a problem.

The locate methods for this table-mapping technique are the same as in the horizontal mapping, so I'll skip this part.

But there is one problem introduced by this table mapping. Finder methods don't behave as they should. Imagine a situation where there's a regular customer with customer ID of "123." Finding a gold customer using this same key will return a (wrong) result! There has to be a way to filter out the other kinds of customers when querying the database. In this example, it would mean ignoring regular and platinum customers when finding a gold customer.

Working around this problem is easy, in most cases. Just add a condition at the end of every EJB-QL query, like this:

EJB-QL Query for Base customers:

SELECT OBJECT(c) FROM BaseCustomerEJBOneTable AS c 
    WHERE c.category = 'B'

EJB-QL Query for Gold customers

SELECT OBJECT(c) FROM GoldCustomerEJBOneTable AS c 
    WHERE c.category = 'G'

EJB-QL Query for Platinum customers

SELECT OBJECT(c) FROM PlatinumCustomerEJBOneTable AS c 
    WHERE c.category = 'P'

But what about findByPrimaryKey()? The container writes this method for you. How do you filter out the unwanted rows? Once more, the only way to work around this problem is to rely on a feature of your application server.

WebLogic Server 7 allows overwriting findByPrimaryKey() using a WebLogic-QL query in weblogic-cmp-rdbms-jar.xml. I'm using this trick in my RTM example. Other vendors may tackle this in other ways. Some may allow manually writing this query in ejb-jar.xml, although that may go against the specification. Some may not support this feature at all, which makes one-table mapping impossible.

Related Reading

Enterprise JavaBeans
By Richard Monson-Haefel

Assessment: This kind of table mapping is often used with a legacy database, which typically has tables with category columns. It requires that the application server provide a way to filter out the rows that are not wanted when running the queries.

Conclusion and Acknowledgments

I didn't invent any of this. Many products exist out there which allow us to use these three techniques (and others) when mapping database tables to hierarchies of classes. I merely applied the three techniques to the special case of entity beans, working around problems as I went.

I specifically want to credit Apple's Enterprise Object Framework (EOF) toolkit for its ingenuity in this field, which inspired me. EOF is a library and tools to map database tables to straight Java (and Objective-C) objects. The maturity of this framework, its flexibility, and its simplicity should be a model for any persistence services provider.

Also worth highlighting, WebLogic Server 7 provided me with all the features needed in order to implement my work-arounds. Kudos to BEA.

Don't get cranky if I didn't mention your favorite persistence services provider tool. I know there are others out there, I just can't explore them all in these few lines.

Next time, we'll see examples of session beans and message-driven beans that use inheritance.

Emmanuel Proulx is an expert in J2EE and Enterprise JavaBeans, and is a certified WebLogic Server 7.0 engineer. He works in the fields of telecommunications and web development.

Return to ONJava.com.