EJB Inheritance, Part 2
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.
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.