java persistence api: inheritance · inheritance strategy: single table 1.1. single table strategy...

28
Java Persistence API: Inheritance Mapping Entity Inheritance to the Database Revision: v2013-10-05 Built on: 2019-08-22 07:10 EST Copyright © 2019 jim stafford ([email protected]) This presentation provides information for mapping Java entity class inheritance to the database using JPA.

Upload: others

Post on 22-Aug-2020

4 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Java Persistence API: Inheritance

Mapping Entity Inheritance to the Database

Revision: v2013-10-05Built on: 2019-08-22 07:10 EST

Copyright © 2019 jim stafford ([email protected])

This presentation provides information for mapping Java entity class inheritance to the database

using JPA.

Page 2: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest
Page 3: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

iii

Purpose ............................................................................................................................ v

1. Goals .................................................................................................................... v

2. Objectives ............................................................................................................. v

1. Inheritance Strategy: Single Table .............................................................................. 1

1.1. Single Table Strategy Overview ........................................................................... 1

1.2. Single Table Example Database Schema ............................................................. 1

1.3. Single Table Example Java Mapping ................................................................... 2

1.4. Single Table Example Usage .............................................................................. 3

1.5. @DiscriminatorColumn Annotation ....................................................................... 4

1.6. Summary ............................................................................................................ 5

2. Inheritance Strategy:Table per Concrete Class ........................................................... 7

2.1. Table per Concrete Class Strategy Overview ........................................................ 7

2.2. Table per Concrete Class Example Database Schema .......................................... 7

2.3. Table per Concrete Class Example Java Mapping ................................................ 8

2.4. Table per Concrete Class Example Usage ........................................................... 9

2.5. Summary .......................................................................................................... 10

3. Inheritance Strategy:Join ........................................................................................... 11

3.1. Join Strategy Overview ..................................................................................... 11

3.2. Join Example Database Schema ....................................................................... 11

3.3. Join Example Java Mapping .............................................................................. 12

3.4. Join Example Usage (Persist) ............................................................................ 13

3.5. Summary .......................................................................................................... 14

4. Inheritance Strategy:Non-Entity ................................................................................. 15

4.1. Non-Entity Strategy Overview ............................................................................ 15

4.2. Non-Entity Example Database Schema .............................................................. 15

4.3. Non-Entity Example Java Mapping ..................................................................... 16

4.4. Non-Entity Example Usage (Persist) .................................................................. 17

4.5. Summary .......................................................................................................... 18

5. Mixed Inheritance Strategies ..................................................................................... 21

5.1. Which Strategy Gets Used for Subclass? ........................................................... 21

5.2. Generated Database Schema ............................................................................ 21

5.3. Summary .......................................................................................................... 22

Page 4: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

iv

Page 5: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

v

Purpose

1. Goals• Introduce mapping entity class inheritance to the database

2. Objectives

At the completion of this topic, the student shall

• have an understanding of:

• Inheritance strategies

• Single Table

• Table per Concrete Class

• Joined

• Mapped Superclass for non-entity parent classes

• be able to:

• Be able to map a Java inheritance relationship using a Single Table strategy

• Be able to map a Java inheritance relationship using a Table per Concrete Class strategy

• Be able to map a Java inheritance relationship using a Table per Subclass (Join) strategy

Page 6: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

vi

Page 7: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Chapter 1.

1

Inheritance Strategy: Single Table

1.1. Single Table Strategy Overview

Figure 1.1. Single Table Inheritance Strategy

• Advantages

• Simplest to implement

• Single table to administer

• Performs better than other inheritance strategies

• No complex joins

• Disadvantages

• Unused fields when sub-types have unique properties

• Sub-type columns must be nullable

• Harder to enforce constraints within database

• SQL "check" constraint can help

check(TYPE != 'BREAD_TYPE' or (BAKEDON is not null and SLICES is not null))

check(TYPE != 'Soup' or (SOUPTYPE is not null and EXPIRATION is not null)

• Not normalized

• More suitable for hierarchies with sub-types that...

• Differ primarily in behavior only

• Do not have unique data requirements

1.2. Single Table Example Database Schema

Figure 1.2. Single Table Example Database Schema

create table ORMINH_PRODUCT (

PTYPE varchar(32) not null,

id bigint generated by default as identity,

Page 8: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Chapter 1. Inheritance Strate...

2

cost double not null,

expiration date,

SOUPTYPE varchar(16),

bakedOn date,

slices integer,

primary key (id)

)

• Single table

• No joins

• Unused columns

1.3. Single Table Example Java Mapping

Figure 1.3. Single Table Example Java Mapping (Parent Class)

@Entity @Table(name="ORMINH_PRODUCT")

@Inheritance(strategy=InheritanceType.SINGLE_TABLE)

@DiscriminatorColumn(name="PTYPE", //column in root table indicating type

discriminatorType=DiscriminatorType.STRING,//data type of column

length=32) //length of discriminator string

public abstract class Product {

@Id @GeneratedValue

private long id;

private double cost;

...

@Transient

public abstract String getName();

• Parent defines default mapping for all derived types

Figure 1.4. Single Table Example Java Mapping (Annotated Derived)

@Entity

@DiscriminatorValue("BREAD_TYPE") //value placed in root table to indicate type

public class Bread extends Product {

private int slices;

@Temporal(TemporalType.DATE)

private Date bakedOn;

...

@Transient

public String getName() { return "Bread"; }

• Supplies type-specific column value

Figure 1.5. Single Table Example Java Mapping (Default Derived)

@Entity

public class Soup extends Product {

public enum SoupType {

UNKNOWN("Unknown"),

Page 9: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Single Table Example Usage

3

CHICKEN_NOODLE("Chicken Noodle"),

NEW_ENGLAND_CLAM_CHOWDER("New England Clam Chowder"),

TOMATO("Tomato");

private String text;

private SoupType(String text) { this.text = text; }

public String text() { return text; }

};

@Enumerated(EnumType.STRING)

@Column(name="SOUPTYPE", length=16)

private SoupType type = SoupType.UNKNOWN;

@Temporal(TemporalType.DATE)

private Date expiration;

...

@Transient

public String getName() { return type.text() + "Soup"; }

• Accepts default type-specific column value

1.4. Single Table Example Usage

Figure 1.6. Single Table Example Usage (Persist)

ejava.examples.orm.inheritance.annotated.Soup soup = new Soup();

soup.setCost(2.12);

final long lifetime = 365L*24*60*60*1000;

soup.setExpiration(new Date(System.currentTimeMillis() + lifetime));

soup.setSoupType(Soup.SoupType.CHICKEN_NOODLE);

em.persist(soup);

ejava.examples.orm.inheritance.annotated.Bread bread = new Bread();

bread.setBakedOn(new Date());

bread.setCost(2.25);

bread.setSlices(24);

em.persist(bread);

Hibernate:

insert into ORMINH_PRODUCT (id, cost, expiration, SOUPTYPE, PTYPE)

values (null, ?, ?, ?, 'Soup')

Hibernate:

insert into ORMINH_PRODUCT(id, cost, bakedOn, slices, PTYPE)

values (null, ?, ?, ?, 'BREAD_TYPE')

• Two rows inserted into single base table with discriminator type supplied

Figure 1.7. Single Table Example Usage (Get Entities)

List<Product> products = em.createQuery(

"select p from Product p", Product.class)

.getResultList();

assertTrue("unexpected number of products:" + products.size(),

products.size() == 2);

Page 10: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Chapter 1. Inheritance Strate...

4

for(Product p: products) {

log.info("product found:" + p);

}

Hibernate:

select

product0_.id as id2_9_,

product0_.cost as cost3_9_,

product0_.expiration as expirati4_9_,

product0_.SOUPTYPE as SOUPTYPE5_9_,

product0_.bakedOn as bakedOn6_9_,

product0_.slices as slices7_9_,

product0_.PTYPE as PTYPE1_9_

from

ORMINH_PRODUCT product0_

-product found:Soup, id=1, cost=2.12, type=CHICKEN_NOODLE, expiration=2014-10-05

-product found:Bread, id=2, cost=2.25, slices=24, baked=2013-10-05

• Single table queried for objects

Figure 1.8. Single Table Example Usage (Verify DB Schema)

//query specific tables for columns

int rows = em.createNativeQuery(

"select ID, TYPE, COST, SOUPTYPE, EXPIRATION, BAKEDON, SLICES " +

" from ORMINH_PRODUCT")

.getResultList().size();

assertEquals("unexpected number of product rows:" + rows, 2, rows);

select * from ORMINH_PRODUCT

PTYPE ID COST BAKEDON SLICES EXPIRATION SOUPTYPE

---------- -- ---- ---------- ------ ---------- --------------

Soup 1 2.12 (null) (null) 2007-10-08 CHICKEN_NOODLE

BREAD_TYPE 2 2.25 2006-10-08 24 (null) (null)

• Single table "sparsely" filled based on type

1.5. @DiscriminatorColumn Annotation

@DiscriminatorColumn defines column to hold type-specific value

name (default="DTYPE")

Column name

discriminatorType

STRING (defaults to Entity.name)

Only portable technique when accepting default

CHAR

Vendor-specific value when accepting default

Page 11: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Summary

5

INTEGER

Vendor-specific value when accepting default

columnDefinition

Database-specific definition for when generating schema

length

Size of STRING

1.6. Summary• Single table represents all sub-classes

• Discriminator columns used to distinguish between types

• No joins

• Good choice when no/minor differences in subclass properties

• Bad choice when subclasses differ greatly in subclass properties

Page 12: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

6

Page 13: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Chapter 2.

7

Inheritance Strategy:Table per

Concrete Class

2.1. Table per Concrete Class Strategy Overview

Figure 2.1. Table per Concrete Class Inheritance Strategy

• 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

2.2. Table per Concrete Class Example Database

Schema

Figure 2.2. Table per Concrete Class Example Database Schema

create table ORMINH_CHECKING (

Page 14: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Chapter 2. Inheritance Strate...

8

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

2.3. Table per Concrete Class Example Java Mapping

Figure 2.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 2.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);

Page 15: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Table per Concrete Class Example Usage

9

}

@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

2.4. Table per Concrete Class Example Usage

Figure 2.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 2.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_

Page 16: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Chapter 2. Inheritance Strate...

10

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

2.5. Summary• Properties pushed down to each concrete class' table

• Requires no joins

• Requires SQL "UNION ALL" of all concrete class table to access common properties across

hierarchy

Page 17: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Chapter 3.

11

Inheritance Strategy:Join

3.1. Join Strategy Overview

Figure 3.1. Joined Inheritance Strategy

• Advantages

• Can be normalized

• Permits constraints to be defined

• Disadvantages

• Requires access to multiple tables when using (insert, select, update, and delete) an entity

• More suitable for sub-classes that...

• Have many unique properties

• Require database constraints

• Are queried for across sibling sub-types

3.2. Join Example Database Schema

Figure 3.2. Join Example Database Schema

create table ORMINH_PERSON (

id bigint generated by default as identity,

firstName varchar(255),

Page 18: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Chapter 3. Inheritance Strate...

12

lastName varchar(255),

primary key (id)

)

create table ORMINH_EMPLOYEE (

hireDate date,

payrate double not null,

id bigint not null,

primary key (id)

)

alter table ORMINH_CUSTOMER

add constraint FK6D5464A42122B7AC

foreign key (id)

references ORMINH_PERSON

alter table ORMINH_EMPLOYEE

add constraint FK9055CB742122B7AC

foreign key (id)

references ORMINH_PERSON

• Table for each entity class is created

• Each table has a primary key

• Sub-class tables use a primary key join with parent class

3.3. Join Example Java Mapping

Figure 3.3. Join Example Java Mapping (Parent Class)

@Entity @Table(name="ORMINH_PERSON")

@Inheritance(strategy=InheritanceType.JOINED)

public class Person {

@Id @GeneratedValue

private long id;

private String firstName;

private String lastName;

• Parent defines default mapping for all derived types

• Parent entity class table also defined

Figure 3.4. Join Example Java Mapping (Subclasses)

@Entity

@Table(name="ORMINH_CUSTOMER") //joined with Person table to form Customer

public class Customer extends Person {

public enum Rating { GOLD, SILVER, BRONZE }

@Enumerated(EnumType.STRING)

private Rating rating;

@Entity

@Table(name="ORMINH_EMPLOYEE") //joined with Person table to form Employee

public class Employee extends Person {

private double payrate;

@Temporal(TemporalType.DATE)

Page 19: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Join Example Usage (Persist)

13

private Date hireDate;

• Sub-classes define their entity-specific tables

3.4. Join Example Usage (Persist)

Figure 3.5. Join Example Usage

ejava.examples.orm.inheritance.annotated.Employee employee = new Employee();

employee.setFirstName("john");

employee.setLastName("doe");

employee.setHireDate(new Date());

employee.setPayrate(10.00);

em.persist(employee);

ejava.examples.orm.inheritance.annotated.Customer customer = new Customer();

customer.setFirstName("jane");

customer.setLastName("johnson");

customer.setRating(Customer.Rating.SILVER);

em.persist(customer);

Hibernate:

insert into ORMINH_PERSON (id, firstName, lastName)

values (null, ?, ?)

Hibernate:

insert into ORMINH_EMPLOYEE (hireDate, payrate, id)

values (?, ?, ?)

Hibernate:

insert into ORMINH_PERSON (id, firstName, lastName)

values (null, ?, ?)

Hibernate:

insert into ORMINH_CUSTOMER (rating, id)

values (?, ?)

• Each persist() must insert into concrete class table and parent class table(s)

Figure 3.6. Join Example Usage (Get Entities)

List<Person> people = em.createQuery("select p from Person p", Person.class).getResultList();

assertTrue("unexpected number of people:" + people.size(),

people.size() == 2);

for(Person p: people) {

log.info("person found:" + p);

}

select

person0_.id as id1_8_,

person0_.firstName as firstNam2_8_,

person0_.lastName as lastName3_8_,

person0_1_.hireDate as hireDate1_6_,

person0_1_.payrate as payrate2_6_,

person0_2_.rating as rating1_5_,

Page 20: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Chapter 3. Inheritance Strate...

14

case

when person0_1_.id is not null then 1

when person0_2_.id is not null then 2

when person0_.id is not null then 0

end as clazz_

from ORMINH_PERSON person0_

left outer join ORMINH_EMPLOYEE person0_1_

on person0_.id=person0_1_.id

left outer join ORMINH_CUSTOMER person0_2_

on person0_.id=person0_2_.id

-person found:Employee, id=1, firstName=john, lastName=doe, payrate=10.0

-person found:Customer, id=2, firstName=jane, lastName=johnson, rating=SILVER

• Parent class table joined with each sub-class table during query of parent type

Figure 3.7. Join Example Usage (Verify DB Schema)

int rows = em.createNativeQuery(

"select ID, FIRSTNAME, LASTNAME from ORMINH_PERSON")

.getResultList().size();

assertEquals("unexpected number of person rows:" + rows, 2, rows);

rows = em.createNativeQuery(

"select ID, RATING from ORMINH_CUSTOMER")

.getResultList().size();

assertEquals("unexpected number of customer rows:" + rows, 1, rows);

rows = em.createNativeQuery(

"select ID, PAYRATE, HIREDATE from ORMINH_EMPLOYEE")

.getResultList().size();

assertEquals("unexpected number of employee rows:" + rows, 1, rows);

select * from ORMINH_PERSON

ID FIRSTNAME LASTNAME

-- --------- --------

1 john doe

2 jane johnson

select * from ORMINH_EMPLOYEE

ID HIREDATE PAYRATE

-- ---------- -------

1 2006-10-08 10.0

select * from ORMINH_CUSTOMER

ID RATING

-- ------

2 SILVER

• Entities span multiple tables

3.5. Summary• Each class is mapped to a separate table

• Tables are joined together (by primary key join default)

• Very similar to @OneToOne relation using @PrimaryKeyJoinColumn

Page 21: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Chapter 4.

15

Inheritance Strategy:Non-Entity

4.1. Non-Entity Strategy Overview

Figure 4.1. Non-Entity Inheritance Strategy

• Advantages

• Allows inheritance of non-entity classes

• Disadvantages

• No base entity to form queries across hierarchy (unlike TABLE_PER_CLASS)

• Tables not normalized (like TABLE_PER_CLASS)

• Parent columns repeated in each subclass table

• More suitable for ...

• Independent subclasses

4.2. Non-Entity Example Database Schema

Figure 4.2. Non-Entity Example Database Schema

create table ORMINH_ALBUM (

ALBUM_ID bigint generated by default as identity,

ALBUM_VERSION bigint,

artist varchar(255),

title varchar(255),

primary key (ALBUM_ID)

)

create table ORMINH_TOOTHPASTE (

id bigint generated by default as identity,

Page 22: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Chapter 4. Inheritance Strate...

16

version bigint not null,

size integer not null,

primary key (id)

)

• Non-entity base class properties appear in subclass tables

4.3. Non-Entity Example Java Mapping

Figure 4.3. Non-Entity Example Java Mapping (Parent Class)

@MappedSuperclass

public abstract class BaseObject {

private long id;

@Access(AccessType.FIELD)

private long version;

@Transient

public long getId() { return id; }

protected void setId(long id) {

this.id = id;

}

• Parent class is not a legal entity -- has no @Id

Note

In this example, the implementation of BaseObject actually has an id attribute

that the derived classes make use of. However, it is marked as @Transient in

the base class and @Id in the derived Entity classes since MappedSuperClasses

do not have primary keys. This specific example could have also used

TABLE_PER_CLASS because of the availability of an id property in the base class.

Figure 4.4. Non-Entity Example Java Mapping (Override Defaults)

@Entity

@Table(name="ORMINH_ALBUM") //this table holds both this entity and parent class

@AttributeOverrides({

@AttributeOverride(name="version", column=@Column(name="ALBUM_VERSION"))

})

public class Album extends BaseObject {

@Access(AccessType.FIELD)

private String artist;

@Access(AccessType.FIELD)

private String title;

@Id @GeneratedValue //id is being generated independent of other siblings

@Column(name="ALBUM_ID")

public long getId() { return super.getId(); }

protected void setId(long id) {

super.setId(id);

Page 23: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Non-Entity Example Usage (Persist)

17

}

• "version" column name from parent being renamed

• "id" property defined in this class given custom column name

• Transient attribute in parent being reused to hold @Id for subclass using PROPERTY access

Figure 4.5. Non-Entity Example Java Mapping (Default Derived)

@Entity

@Table(name="ORMINH_TOOTHPASTE") //table holds this entity and parent class

public class ToothPaste extends BaseObject {

@Access(AccessType.FIELD)

private int size;

@Id @GeneratedValue //id is being generated independent of other siblings

public long getId() { return super.getId(); }

protected void setId(long id) {

super.setId(id);

}

• Entity accepts mapping defaults

4.4. Non-Entity Example Usage (Persist)

Figure 4.6. Non-Entity Example Usage

ejava.examples.orm.inheritance.annotated.Album album = new Album();

album.setArtist("Lynyrd Skynyrd");

album.setTitle("One More for the Road");

em.persist(album);

ejava.examples.orm.inheritance.annotated.ToothPaste toothpaste = new ToothPaste();

toothpaste.setSize(10);

em.persist(toothpaste);

Hibernate:

insert into ORMINH_ALBUM (ALBUM_ID, ALBUM_VERSION, artist, title)

values (null, ?, ?, ?)

Hibernate:

insert into ORMINH_TOOTHPASTE (id, version, size)

values (null, ?, ?)

• Rows are inserted into type-specific entity class tables

Figure 4.7. Non-Entity Example Usage (Get Entities)

List<BaseObject> objects = em.createQuery("select a from Album a").getResultList();

objects.addAll( em.createQuery("select tp from ToothPaste tp").getResultList());

assertTrue("unexpected number of objects:" + objects.size(), objects.size() == 2);

Page 24: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Chapter 4. Inheritance Strate...

18

for(BaseObject o: objects) {

log.info("object found:" + o);

}

Hibernate:

select

album0_.ALBUM_ID as ALBUM1_1_,

album0_.ALBUM_VERSION as ALBUM2_1_,

album0_.artist as artist3_1_,

album0_.title as title4_1_

from ORMINH_ALBUM album0_

Hibernate:

select

toothpaste0_.id as id1_12_,

toothpaste0_.version as version2_12_,

toothpaste0_.size as size3_12_

from ORMINH_TOOTHPASTE toothpaste0_

-object found:ejava.examples.orm.inheritance.annotated.Album@3822f407, id=1, name=Lynyrd Skynyrd:One More for

the Road

-object found:ejava.examples.orm.inheritance.annotated.ToothPaste@22a79bc, id=1, name=10oz toothpaste

• Separate tables are accessed when obtaining each type

Figure 4.8. Non-Entity Example Usage (Verify DB Schema)

int rows = em.createNativeQuery(

"select ALBUM_ID, ALBUM_VERSION, ARTIST, TITLE " +

" from ORMINH_ALBUM")

.getResultList().size();

assertEquals("unexpected number of album rows:" + rows, 1, rows);

rows = em.createNativeQuery(

"select ID, VERSION, SIZE " +

" from ORMINH_TOOTHPASTE")

.getResultList().size();

assertEquals("unexpected number of toothpaste rows:" + rows, 1, rows);

select * from ORMINH_ALBUM

ALBUM_ID ALBUM_VERSION ARTIST TITLE

-------- ------------- -------------- ---------------------

1 0 Lynyrd Skynyrd One More for the Road

select * from ORMINHTOOTHPASTE

ID VERSION SIZE

-- ------- ----

1 0 10

• Separate tables per concrete class (like TABLE_PER_CLASS)

• No unused columns (like TABLE_PER_CLASS)

4.5. Summary• Similar mapping to TABLE_PER_CLASS

Page 25: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Summary

19

• Parent class not an @Entity

• Parent/base class not mapped -- cannot use as query type

Page 26: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

20

Page 27: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Chapter 5.

21

Mixed Inheritance Strategies

5.1. Which Strategy Gets Used for Subclass?

Figure 5.1. Mixed Inheritance Strategy

5.2. Generated Database Schema

Figure 5.2. Generated Database Schema

create table ORMINH_SHAPE (

id bigint generated by default as identity,

version bigint not null,

posx integer not null,

posy integer not null,

primary key (id)

)

create table ORMINH_CIRCLE (

radius integer not null,

Page 28: Java Persistence API: Inheritance · Inheritance Strategy: Single Table 1.1. Single Table Strategy Overview Figure 1.1. Single Table Inheritance Strategy • Advantages • Simplest

Chapter 5. Mixed Inheritance ...

22

id bigint not null,

primary key (id)

)

create table ORMINH_RECTANGLE (

height integer not null,

width integer not null,

id bigint not null,

primary key (id)

)

alter table ORMINH_CIRCLE

add constraint FKFF2F1F1632C97600

foreign key (id)

references ORMINH_SHAPE

alter table ORMINH_RECTANGLE

add constraint FK1FFF614932C97600

foreign key (id)

references ORMINH_SHAPE

create table ORMINH_CUBE (

depth integer not null,

id bigint not null,

primary key (id)

)

alter table ORMINH_CUBE

add constraint FK84203FB112391CE

foreign key (id)

references ORMINH_RECTANGLE

• Provider used parent's JOIN strategy over child's TABLE_PER_CLASS specification

5.3. Summary• Provider behavior undefined by spec

• Leverage DAOs to bridge the mis-match between legacy DB schema and Java class model