An inheritance strategy maps an object-oriented class hierarchy to relational tables. Because relational SQL models provide has-a relationships rather than general type inheritance, the mapping must represent polymorphism through concrete tables, discriminators, unions, or joins. section 7.0
The principal mapping choices are:
- TABLE_PER_CLASS stores each concrete class separately. It can discard polymorphism or use SQL UNION queries to preserve runtime polymorphic behavior. section 7.0
- SINGLE_TABLE stores the hierarchy in one denormalized table and uses a discriminator to identify supertypes and subtypes. Subclass columns generally must be nullable. section 7.0 section 7.7
- JOINED stores the superclass and subclass data in separate tables, representing inheritance with foreign keys and retrieving polymorphic instances through SQL joins. section 7.0 section 7.7
Choose based on polymorphic queries and associations, the number of subtype attributes, normalization requirements, and the relative cost of joins versus unions. Prefer SINGLE_TABLE for simple hierarchies with few subtype properties; consider JOINED for many non-optional subtype properties and stronger normalization; evaluate TABLE_PER_CLASS when polymorphism is unnecessary or unions are preferable. section 7.7
Breaking out a subclass from SINGLE_TABLE
A BillingDetails hierarchy can use InheritanceType.SINGLE_TABLE while moving CreditCard fields into a CREDITCARD secondary table. @SecondaryTable and @Column(table = "CREDITCARD") map those fields; CREDITCARD_ID is both the primary key and a foreign key to the hierarchy table. Hibernate fetches polymorphically with a left outer join, while the separated columns can be declared NOT NULL. section 7.5
Listing 7.18 Mapping CreditCard
Path: Ch07/mapping-inheritance-mixed/src/main/java/com/manning /javapersistence/ch07/model/CreditCard.java @Entity @DiscriminatorValue("CC") @SecondaryTable( name = "CREDITCARD", pkJoinColumns = @PrimaryKeyJoinColumn(name = "CREDITCARD_ID") ) public class CreditCard extends BillingDetails { @NotNull @Column(table = "CREDITCARD", nullable = false) private String cardNumber; @Column(table = "CREDITCARD", nullable = false) private String expMonth; @Column(table = "CREDITCARD", nullable = false) private String expYear; // . . . }
Inspect the Java annotation mapping for moving CreditCard properties into a secondary table. section 7.5
