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 1001. A single relation mapping.

Todo: Ref/Fig/billingData.fig

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


The relation may be created by the following DDL:

Figure 1002. Mapping the inheritance hierarchy.

Todo: Ref/Fig/billingSql.fig


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 1003. 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(); ...