- EJB 3 Developer Guide
- Michael Sikora
- 956字
- 2021-07-02 11:34:57
O/R Inheritance Mapping
Inheritance is a distinctive aspect of object oriented technology. Inheritance could not be utilized in earlier versions of EJB as an EJB 2.x entity bean cannot extend another EJB 2.x entity bean. With EJB 3, entities are more object oriented in that one entity can extend another. However, this leaves us with the matter of mapping entities in an inheritance hierarchy onto a relational database.
There are a number of strategies we can use to map an inheritance hierarchy onto relational database tables. As an example, suppose the Account class has CheckingAccount and SavingsAccount subclasses:

CheckingAccount and SavingsAccount extend the base Account class. As the names suggest, they are entities that represent checking accounts and savings accounts respectively.
SINGLE_TABLE Strategy
The first inheritance mapping option is the Single Table strategy. All the classes in a hierarchy are mapped to a single table. The table must have a discriminator column whose value for a given row identifies the associated subclass. The ACCOUNT
table below results from implementing the Single Table strategy for the above Account inheritance hierarchy. A couple of rows have been added for illustration.
ACCOUNT Table

ACCOUNT_TYPE
is the discriminator column. A value of C indicates a checking account, a value of S indicates a saving account.
This strategy is efficient for both read and write operations because there is no need to perform joins. It is a rather wasteful use of database storage especially if there are many subclasses each containing a large number of attributes. Columns corresponding to subclass attributes, such as INTERESTRATE
and OVERDRAFTLIMIT
in our example, must be nullable.
We now turn to the code required to implement this strategy. The Account entity is shown below:
@Entity @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name="ACCOUNT_TYPE") public abstract class Account implements Serializable { protected int id; protected double balance; protected String accountType; // getters and setters @Column(name="ACCOUNT_TYPE", length=2) public String getAccountType() { return accountType; } ... }
Note the Account entity is an abstract class. This is because the Account entity will never be instantiated, only CheckingAccount and SavingsAccount entities will be instantiated. Consequently there is no constructor for the Account entity. The @Inheritance
annotation indicates that a Single Table mapping strategy is used. The @DiscriminatorColumn
annotation specifies that the ACCOUNT_TYPE
column acts as the discriminator column. Note that we need to use the @Column
annotation to map the accountType
field with the ACCOUNT_TYPE
column.
Now take a look at the CheckingAccount entity:
@Entity
@DiscriminatorValue("C")
public class CheckingAccount extends Account {
private double overdraftLimit;
public CheckingAccount() {
}
// getter and setter
}
Note the use of the @DiscriminatorValue
annotation to indicate that a checking account has a value of C
in the discriminator column. As CheckingAccount is a concrete class, it contains a constructor.
The code for SavingsAccount has a similar structure to CheckingAccount:
@Entity
@DiscriminatorValue("S")
public class SavingsAccount extends Account {
private double interestRate;
public SavingsAccount() {}
// getter and setter
}
This time the @DiscriminatorValue
annotation indicates that a savings account has a value of S
in the discriminator column.
An important feature of the Single Table strategy is that polymorphic queries are supported. By a polymorphic query we mean that the FROM
clause of the query includes not only instances of the concrete entity class to which it refers, but all subclasses of that class as well. If the query refers to an abstract entity class then it is polymorphic if it includes just the subclasses of that class. So the query,
SELECT a FROM Account a
will retrieve both CheckingAccounts and SavingsAccounts. We will cover queries in some detail in Chapter 5.
JOINED Strategy
In this strategy the root of the class hierarchy is represented by a single table. Each subclass is represented by a separate table which contains columns corresponding to fields which are specific to the subclass. The subclass table also contains a column that represents the primary key. The primary key column also acts as a foreign key to the root primary key. A Joined strategy for the Account inheritance hierarchy results in the following tables:
ACCOUNT Table

CHECKINGACCOUNT Table

SAVINGSACCOUNT Table

Note in both the CHECKINGACCOUNT
and SAVINGSACCOUNT
tables, ACCOUNT_ID
is a foreign key referencing ACCOUNT(ACCOUNT_ID)
.
This strategy is efficient with respect to data storage, however as queries require joins, they are inefficient especially when inheritance hierarchies are wide or deep. Like the Single Table strategy, the Joined strategy also supports polymorphic queries.
We will take a look at the code to implement a Joined strategy for the Account inheritance hierarchy. First we take the Account entity:
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="ACCOUNT_TYPE")
public abstract class Account implements Serializable {
protected int id;
protected double balance;
protected String accountType;
// getters and setters
}
There is only one change from the Single Table strategy case, we specify a Joined strategy in the @Inheritance
annotation. No changes are required for the CheckingAccount and SavingsAccount entities.
Table per Concrete Class Strategy
The final strategy is for each concrete subclass to have its own table. Each class has all its properties, including inherited properties, mapped to columns of the corresponding table. For the Account inheritance hierarchy this will result in the following tables:
CHECKINGACCOUNT Table

SAVINGSACCOUNT Table

Note there is no ACCOUNT
table. This strategy is efficient in terms of data storage and has the added advantage that a discriminator column is not required. However, this strategy does not support polymorphism very well. It is also inefficient when queries span more than one table as an SQL UNION
is typically required.
This strategy is optional. The EJB 3 specification does not require persistence providers to support this strategy. As the GlassFish application server, with the embedded Toplink persistence engine, does not support this strategy we will not go further into coding details.
- EJB 3.0 Database Persistence with Oracle Fusion Middleware 11g: LITE
- GIMP 2.6 cookbook
- 中文版3ds Max 2024完全自學教程
- DWR Java AJAX Applications
- jQuery Mobile First Look
- RESTful PHP Web Services
- OpenCart 1.4 Template Design Cookbook
- PostgreSQL 9.0 High Performance
- 電腦寫作與定制五筆(第2版)
- Hello HarmonyOS!:鴻蒙應用開發從入門到精通
- OpenVPN 2 Cookbook
- Apache Geronimo 2.1: Quick Reference
- 零基礎攝影后期調色 Photoshop照片處理輕松入門
- 水晶石技法:3ds Max動畫特效實戰手冊
- 軟件可靠性的不確定性研究