Chapter 6. Mapping inheritance

 

In this chapter

  • Inheritance-mapping strategies
  • Polymorphic associations

We deliberately haven’t talked much about inheritance mapping so far. Mapping a hierarchy of classes to tables can be a complex issue, and we present various strategies in this chapter.

A basic strategy for mapping classes to database tables might be “one table for every entity persistent class.” This approach sounds simple enough and indeed works well, until we encounter inheritance.

Inheritance is such a visible structural mismatch between the object-oriented and relational worlds because object-oriented systems model both is a and has a relationships. SQL-based models provide only has a relationships; SQL database management systems don’t support type inheritance—and even when it’s available, it’s usually proprietary or incomplete.

There are four different strategies for representing an inheritance hierarchy:

  • Use one table per concrete class and default runtime polymorphic behavior.
  • Use one table per concrete class but discard polymorphism and inheritance relationships completely from the SQL schema. Use SQL UNION queries for runtime polymorphic behavior.
  • Use one table per class hierarchy: enable polymorphism by denormalizing the SQL schema and relying on row-based discrimination to determine super/subtypes.
  • Use one table per subclass: represent is a (inheritance) relationships as has a (foreign key) relationships, and use SQL JOIN operations.

6.1. Table per concrete class with implicit polymorphism

Path: /model/src/main/java/org/jpwh/model/inheritance/mappedsuperclass/BillingDetails.java

@MappedSuperclass
public abstract class BillingDetails {
<enter/>
    @NotNull
    protected String owner;
<enter/>
    // ...
}
<enter/>

Path: /model/src/main/java/org/jpwh/model/inheritance/mappedsuperclass/CreditCard.java

@Entity
@AttributeOverride(
        name = "owner",
        column = @Column(name = "CC_OWNER", nullable = false))
public class CreditCard extends BillingDetails {
<enter/>
    @Id
    @GeneratedValue(generator = Constants.ID_GENERATOR)
    protected Long id;
<enter/>
    @NotNull
    protected String cardNumber;
<enter/>
    @NotNull
    protected String expMonth;
<enter/>
    @NotNull
    protected String expYear;
<enter/>
    // ...
}

6.2. Table per concrete class with unions

Path: /model/src/main/java/org/jpwh/model/inheritance/tableperclass/BillingDetails.java

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class BillingDetails {
<enter/>
    @Id
    @GeneratedValue(generator = Constants.ID_GENERATOR)
    protected Long id;
<enter/>
    @NotNull

    protected String owner;
<enter/>
    // ...
}

Path: /model/src/main/java/org/jpwh/model/inheritance/tableperclass/CreditCard.java

@Entity
public class CreditCard extends BillingDetails {
<enter/>
    @NotNull
    protected String cardNumber;
<enter/>
    @NotNull
    protected String expMonth;
<enter/>
    @NotNull
    protected String expYear;
<enter/>
    // ...
}

6.3. Table per class hierarchy

Path: /model/src/main/java/org/jpwh/model/inheritance/singletable/BillingDetails.java

Path: /model/src/main/java/org/jpwh/model/inheritance/singletable/CreditCard.java

Path: /model/src/main/java/org/jpwh/model/inheritance/singletableformula/BillingDetails.java

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@org.hibernate.annotations.DiscriminatorFormula(
        "case when CARDNUMBER is not null then 'CC' else 'BA' end"
)
public abstract class BillingDetails {
    // ...
}

6.4. Table per subclass with joins

sitemap