Single table per class hierarchy

This approach may be considered the most simple: We just create one database table for storing instances of arbitrary classes belonging to the inheritance hierarchy in question:

Figure 1087. A single relation mapping.

(Animated PDF Version)

A single relation mapping.

Fitting both inherit.v1.CreditCard and inherit.v1.BankAccount instances into a single relation.


The relation may be created by the following DDL:

Figure 1088. Mapping the inheritance hierarchy.

We take a closer look at the generated relation. Since

Java
package inherit.v1;
            ...
	    @Entity
	    @Inheritance(strategy=InheritanceType.SINGLE_TABLE) 
	    @DiscriminatorColumn(name="dataType", discriminatorType=DiscriminatorType.STRING) 
	    abstract class BillingDetails {
	    @Id @GeneratedValue  public Long getId() ...
	    @Column(nullable = false, length = 32)public final String getNumber() ...
	    @Temporal(TemporalType.TIMESTAMP)
	    @Column(nullable = false) public Date getCreated() ...
package inherit.v1;
	    ...
	    @Entity
	    @DiscriminatorValue(value = "Credit card" ❶)
	    public class CreditCard extends BillingDetails {
	    ... //Nothing JPA related happens here
package inherit.v1;
	    ...
	    @Entity
	    @DiscriminatorValue(value = "Bank account" ❶)
	    public class BankAccount extends BillingDetails {
	    ... //Nothing JPA related happens here
Sql
CREATE TABLE BillingDetails  (
	    dataType varchar(31) NOT NULL,
	    id bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
	    number varchar(255) NOT NULL, 
	    created datetime NOT NULL, 
	    cardType int(11) DEFAULT NULL, 
	    expiration datetime DEFAULT NULL, 
	    bankName varchar(255) DEFAULT NULL, 
	    swiftcode varchar(255) DEFAULT NULL 
	    )

All classes of the inheritance hierarchy will be mapped to a single table. Unless stated otherwise the JPA provider will choose the root class' name (BillingDetails) as default value for the generated relation's name .

The JPA provider needs a column to distinguish the different types of database objects. We've chosen the discriminator attribute dataType values to be simple strings. Due to the definitions in ❶ and ❶ database object types are being identified by either of the two values:

  • Credit card: object will be mapped to inherit.v1.CreditCard.

  • Bank account: object will be mapped to inherit.v1.BankAccount.

In a productive system the javax.persistence.DiscriminatorType setting will typically favour javax.persistence.DiscriminatorType.INTEGER over javax.persistence.DiscriminatorType.STRING unless the application in question has to deal with a legacy database schema.

This one is unrelated to inheritance: Our primary key values will be auto generated by the database server e.g. by SEQUENCE or IDENTITY mechanisms if available.

Only the base class' attributes may exclude NULL values.

All derived classes' attributes must allow NULL values.

We may now insert instances of inherit.v1.BankAccount or inherit.v1.CreditCard:

Figure 1089. Inserting payment information
package inherit.v1;
	  ...
	  public class Persist {
	  public static void main(String[] args) throws ParseException {
	  ... final Transaction transaction = session.beginTransaction();
	  {
          final CreditCard creditCard = new CreditCard("4412 8334 4512 9416", 1, "05/18/15");
          session.save(creditCard);
          
          final BankAccount bankAccount = new BankAccount("1107 2 31", "Lehman Brothers", "BARCGB22");
          session.save(bankAccount);
	  }
	  transaction.commit(); ...