Enterprise Java Development@TOPIC@
Advantages
May have constrained columns
No joins when accessing a single concrete type
Disadvantages
Not normalized
Redundant columns in each concrete child table
More work required to query across tables
Requires use of SQL "UNION"
Least desirable from a performance/portability standpoint
More suitable for ...
Sub-types not needed to be manipulated with sibling other sub-types
Figure 64.2. Table per Concrete Class Example Database Schema
create table ORMINH_CHECKING ( id bigint not null, balance double not null, fee double not null, primary key (id) ) create table ORMINH_INTERESTACCT ( id bigint not null, balance double not null, rate double not null, primary key (id) ) create sequence ORMINH_SEQ
Table for each concrete class
No separate table for parent class
Parent columns repeated in concrete sub-class tables
* his particular example uses SEQUENCE for primary key generation
Figure 64.3. Table per Concrete Class Example Java Mapping (Parent Class)
@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
@SequenceGenerator(
name="orminhSeq", //required logical name
sequenceName="ORMINH_SEQ" //name in database
)
public abstract class Account {
@Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="orminhSeq")
private long id;
private double balance;
...
public void deposit(double amount) throws AccountException {
setBalance(getBalance() + amount);
}
public abstract void withdraw(double amount) throws AccountException;
...
Parent defines default mapping for all derived types, including PK generation
Using a common SEQUENCE allows sub-classes to have unique PKs across all tables
Figure 64.4. Table per Concrete Class Example Java Mapping (Subclasses)
@Entity
@Table(name="ORMINH_CHECKING")
public class CheckingAccount extends Account {
private double fee;
public void withdraw(double amount) throws AccountException {
super.setBalance(super.getBalance() - fee);
}
@Entity
@Table(name="ORMINH_INTERESTACCT")
public class InterestAccount extends Account {
private double rate;
public void withdraw(double amount) throws AccountException {
super.setBalance(super.getBalance() - amount);
}
Subclasses name their specific entity class table
Figure 64.5. Table per Concrete Class Example Usage (Persist)
ejava.examples.orm.inheritance.annotated.CheckingAccount checking = new CheckingAccount();
checking.setFee(0.50);
em.persist(checking);
ejava.examples.orm.inheritance.annotated.InterestAccount savings = new InterestAccount();
savings.setRate(0.25);
em.persist(savings);
Hibernate: call next value for ORMINH_SEQ Hibernate: insert into ORMINH_CHECKING (balance, fee, id) values (?, ?, ?) Hibernate: insert into ORMINH_INTERESTACCT (balance, rate, id) values (?, ?, ?)
Rows for entities placed into separate tables
Figure 64.6. Table per Concrete Class Example Usage (Get Entities)
List<Account> accounts =em.createQuery("select a from Account a").getResultList();
assertTrue("unexpected number of accounts:" + accounts.size(), accounts.size() == 2);
for(Account a: accounts) {
log.info("account found:" + a);
}
select account0_.id as id1_0_, account0_.balance as balance2_0_, account0_.rate as rate1_7_, account0_.fee as fee1_2_, account0_.clazz_ as clazz_ from ( select id, balance, rate, null as fee, 1 as clazz_ from ORMINH_INTERESTACCT union all select id, balance, null as rate, fee, 2 as clazz_ from ORMINH_CHECKING ) account0_ -account found:InterestAccount, id=51, balance=0.0, rate=0.25 -account found:CheckingAccount, id=50, balance=0.0, fee=0.5
Query through parent type causes SQL "UNION ALL" of each concrete sub-class table
Figure 64.7. Table per Concrete Class Example Usage (Verify DB Schema)
//query specific tables for columns
int rows = em.createNativeQuery(
"select ID, BALANCE, FEE from ORMINH_CHECKING")
.getResultList().size();
assertEquals("unexpected number of checking rows:" + rows, 1, rows);
rows = em.createNativeQuery(
"select ID, BALANCE, RATE from ORMINH_INTERESTACCT")
.getResultList().size();
assertEquals("unexpected number of interestacct rows:" + rows, 1, rows);
select * from ORMINH_CHECKING ID BALANCE FEE -- ------- --- 50 0.0 0.5 select * from ORMINH_INTERESTACCT ID BALANCE RATE -- ------- ---- 51 0.0 0.25
Table per concrete class
No unused columns
Parent columns repeated in each sub-class table