Module 05 - Hibernate Inheritance-upd
Module 05 - Hibernate Inheritance-upd
© 2014 Time2Master 1
Inheritance
Using inheritance a class can extend another class
Thereby inheriting all its properties and method
Often referred to as an ‘is-a’ relationship
Account is an <<abstract>>
Account
abstract class +number
+balance Checking Account
is an Account
Savings Account
also has a number SavingsAccount CheckingAccount
© 2014 Time2Master 2
Polymorphism
Polymorphism is the ability of a subtype to
appear and behave like its supertype
This enables Person to have a list of Account
references, which may hold SavingsAccounts
and CheckingAccounts.
A polymorphic query is a query for all objects
in a hierarchy, independent of their subtype
Person <<abstract>>
owns Account
+firstName
+lastName +number
1 1..*
+balance
Checking Account is an Account
and can be treated as such
SavingsAccount CheckingAccount
+APY +overdraftLimit
© 2014 Time2Master 3
Three ways to map
You can map inheritance in one of three ways:
Single Table per Hierarchy <<abstract>>
Account
+number
De-normalized schema
+balance
Joined Tables
Normalized & similar to classes
Slower queries
© 2014 Time2Master 5
Single Table Implementation
Single Table per Hierarchy uses one big table
Discriminator column specifies actual type
Sub class properties added as nullable columns
<<abstract>>
Account
+number
+balance Account type
specifies the
actual type
APY and overdraft
SavingsAccount CheckingAccount limit are nullable
+APY +overdraftLimit
© 2014 Time2Master 6
Single Table in Action
© 2014 Time2Master 7
SQL for Single Table
select
account0_.number as number0_,
account0_.balance as balance0_,
account0_.owner_id as owner6_0_,
account0_.overdraftLimit as overdraf4_0_,
account0_.APY as APY0_,
account0_.account_type as account1_0_
from
Account account0_
© 2014 Time2Master 8
Single Table Mapping
Specify the SINGLE_TABLE strategy
@Entity
<<abstract>>
@Inheritance(strategy=InheritanceType.SINGLE_TABLE) Account
@DiscriminatorColumn( +number
name="account_type", +balance
discriminatorType=DiscriminatorType.STRING
)
public abstract class Account { Optional annotation
@Id
@DiscriminatorColumn SavingsAccount CheckingAccount
@GeneratedValue
private long number; +APY +overdraftLimit
...
@Entity
@DiscriminatorValue(“savings") Specify discriminator value
public class SavingsAccount extends Account {
private double APY;
...
@Entity
@DiscriminatorValue(“checking") Specify discriminator value
public class CheckingAccount extends Account {
private double overdraftLimit;
...
© 2014 Time2Master 9
XML
<hibernate-mapping package="single">
<class name="Account" abstract="true"> Abstract account class
<id name="number">
<generator class="native" />
</id>
<discriminator> tag has to be
<discriminator type="string" column="account_type" /> after <id> and before <property>
SavingsAccount CheckingAccount
+APY +overdraftLimit
© 2014 Time2Master 10
Inheritance Mapping
JOINED TABLES
© 2014 Time2Master 11
Joined Tables Implementation
The Joined Tables Strategy uses FK ‘has a’
relations to emulate ‘is a’ relations
Uses Foreign Key constraints on the Primary Keys
Queries use JOINs to included needed tables
<<abstract>> CheckingAccount’s
Account
primary key has a FK
+number
+balance constraint to Account
SavingsAccount CheckingAccount
+APY +overdraftLimit
SavingsAccount’s primary
key has a foreign key
constraint to Account
© 2014 Time2Master 12
Joined Tables in Action
Account Table SavingsAccount CheckingAccount
+ Normalized Schema
+ Database view is similar to domain view
– Inserting or updating an entity results in multiple
insert or update statements
– Necessary joins can give lower query performance
© 2014 Time2Master 13
Joined – No Discriminator Value
select
account0_.number as number0_,
account0_.balance as balance0_,
account0_.owner_id as owner3_0_,
account0_1_.overdraftLimit as overdraf1_1_,
account0_2_.APY as APY2_,
case
when account0_1_.number is not null then 1
when account0_2_.number is not null then 2
when account0_.number is not null then 0
end as clazz_
from
Account account0_
left outer join
CheckingAccount account0_1_
on account0_.number=account0_1_.number
left outer join
SavingsAccount account0_2_
on account0_.number=account0_2_.number
© 2014 Time2Master 14
Joined
Just specify the inheritance
strategy, nothing else
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Account { <<abstract>>
@Id Account
@GeneratedValue +number
private long number; +balance
private double balance;
...
SavingsAccount CheckingAccount
+APY +overdraftLimit
@Entity
public class SavingsAccount extends Account {
private double APY;
...
Subclasses can be mapped as normal
entity classes, but without identifiers
@Entity
public class CheckingAccount extends Account {
private double overdraftLimit;
...
© 2014 Time2Master 15
XML
<hibernate-mapping package="single">
<class name="Account" abstract="true"> Abstract account class
<id name="number">
<generator class="native" />
</id>
<joined-subclass name="CheckingAccount">
<key column="number" />
Need an additional <key> tag to specify
<property name="overdraftLimit" />
</joined-subclass> the PK / join column in the subclasses
</class>
</hibernate-mapping>
<<abstract>>
Account
+number
+balance
SavingsAccount CheckingAccount
+APY +overdraftLimit
© 2014 Time2Master 16
Inheritance Mapping
© 2014 Time2Master 17
Table per Concrete Class
Table per Concrete Class uses a table for each
concrete (non-abstract) class
Subclass tables include all superclass properties
Polymorphic queries use UNION operations
If the account class
was not abstract
<<abstract>> there would also be
Account
an account table
+number
+balance
SavingsAccount CheckingAccount
+APY +overdraftLimit
© 2014 Time2Master 18
Concrete Class in Action
SavingsAccount CheckingAccount
© 2014 Time2Master 19
Table Per Concrete – No Discriminator Value
select
account0_.number as number0_,
account0_.balance as balance0_,
account0_.owner_id as owner3_0_,
account0_.overdraftLimit as overdraf1_1_,
account0_.APY as APY2_,
account0_.clazz_ as clazz_
from
( select
number,
balance,
owner_id,
overdraftLimit,
cast(null as int) as APY,
1 as clazz_
from
CheckingAccount
union
all select
number,
balance,
owner_id,
cast(null as int) as overdraftLimit,
APY,
2 as clazz_
from
SavingsAccount
) account0_
© 2014 Time2Master 20
Table per Class
Just specify the inheritance
strategy, nothing else
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) <<abstract>>
Account
public class Account {
+number
@Id +balance
@GeneratedValue(strategy=GenerationType.TABLE)
private long number;
private double balance; Id generation can not
use identity column
... SavingsAccount CheckingAccount
+APY +overdraftLimit
@Entity
public class CheckingAccount extends Account {
private Double overdraftLimit;
Java.util.Double instead
...
of primitive double type
© 2014 Time2Master 21
XML
<hibernate-mapping package="concrete">
<class name="Account" abstract="true">
<id name="number">
<generator class="hilo" /> Identity generation can
</id> not use identity column
<property name="balance" />
<union-subclass name="SavingsAccount">
<property name="APY" /> <union-subclass> tag
</union-subclass>
<union-subclass name="CheckingAccount">
<property name="overdraftLimit" />
</union-subclass>
</class>
</hibernate-mapping>
<<abstract>>
Account
+number
+balance
SavingsAccount CheckingAccount
+APY +overdraftLimit
© 2014 Time2Master 22
Inheritance Mapping
WRAPPING UP
© 2014 Time2Master 23
Recommendations
If subclasses don’t contain a lot of properties
use single table per hierarchy
If subclasses have many properties it is
generally best to use joined tables
Generally avoid using table per concrete class
unless you do not have any polymorphic
associations
© 2014 Time2Master 24
Active Learning
What are the advantages and disadvantages
of the joined table strategy?
© 2014 Time2Master 25
Module Summary
In this module we covered the different ways
to map inheritance with Hibernate
Single Table: De-normalized schema, but very
efficient queries
Joined Tables: Normalized schema, but less
efficient queries
Table per Concrete: has some issues, but is very
efficient if polymorphism is not a priority
Which strategy to use depends on your
business needs, when in doubt the joined
table is the most flexible, although slower
© 2014 Time2Master 26