Thursday, October 26, 2017

Hibernate Inheritance Mapping

Inheritance

MappedSuperclass

Totally separated tables in database. Two tables will be created for DebitAccount and CreditAccount. No fetching against subclass is available.

@MappedSuperclass
public static class Account {
 
    @Id
    private Long id;
 
}
 
@Entity(name = "DebitAccount")
public static class DebitAccount extends Account {
 
    private BigDecimal overdraftFee;
}
 
@Entity(name = "CreditAccount")
public static class CreditAccount extends Account {
 
    private BigDecimal creditLimit;
}

Single Table (default choice for JPA)

Each subclass in a hierarchy must define a unique discriminator value, which is used to differentiate between rows belonging to separate subclass types. If this is not specified, the DTYPE column is used as a discriminator, storing the associated subclass name.

@Entity(name = "Account")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public static class Account {
 
    @Id
    private Long id;
}
 
@Entity(name = "DebitAccount")
public static class DebitAccount extends Account {
 
    private BigDecimal overdraftFee;
}
 
@Entity(name = "CreditAccount")
public static class CreditAccount extends Account {
 
    private BigDecimal creditLimit;
}

@Entity(name = "Account")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorFormula(
    "case when debitKey is not null " +
    "then 'Debit' " +
    "else ( " +
    "   case when creditKey is not null " +
    "   then 'Credit' " +
    "   else 'Unknown' " +
    "   end ) " +
    "end "
)
//@DiscriminatorColumn(
//    name="type",
//    discriminatorType=DiscriminatorType.STRING)
// only STRING, CHAR, INTEGER are valid
public static class Account {
 
    @Id
    private Long id;
}
 
@Entity(name = "DebitAccount")
@DiscriminatorValue(value = "Debit")
public static class DebitAccount extends Account {
 
    private String debitKey;
}
 
@Entity(name = "CreditAccount")
@DiscriminatorValue(value = "Credit")
public static class CreditAccount extends Account {
 
    private String creditKey;
}


@Entity(name = "Account")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorValue( "null" )
public static class Account {
 
    @Id
    private Long id;
}
 
@Entity(name = "DebitAccount")
@DiscriminatorValue( "Debit" )
public static class DebitAccount extends Account {
 
    private BigDecimal overdraftFee;
}
 
@Entity(name = "CreditAccount")
@DiscriminatorValue( "Credit" )
public static class CreditAccount extends Account {
 
    private BigDecimal creditLimit;
 
}
 
@Entity(name = "OtherAccount")
@DiscriminatorValue( "not null" )
public static class OtherAccount extends Account {
 
    private boolean active;
}

Joined Table

Tables for subclasses will have a foreign key column that points back to superclass.

@Entity(name = "Account")

@Inheritance(strategy = InheritanceType.JOINED)
public static class Account {
 
    @Id
    private Long id;
}
 
@Entity(name = "DebitAccount")
public static class DebitAccount extends Account {
 
    private BigDecimal overdraftFee;
}
 
@Entity(name = "CreditAccount")
public static class CreditAccount extends Account {
 
    private BigDecimal creditLimit;
}


@Entity(name = "Account")

@Inheritance(strategy = InheritanceType.JOINED)
public static class Account {
 
    @Id
    private Long id;
}
 
@Entity(name = "DebitAccount")
@PrimaryKeyJoinColumn(name = "account_id")
public static class DebitAccount extends Account {
 
    private BigDecimal overdraftFee;
}
 
@Entity(name = "CreditAccount")
@PrimaryKeyJoinColumn(name = "account_id")
public static class CreditAccount extends Account {
 
    private BigDecimal creditLimit;
}

Table per (concrete) class

@Entity(name = "Account")

@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public static class Account {
 
    @Id
    private Long id;
}
 
@Entity(name = "DebitAccount")
public static class DebitAccount extends Account {
 
    private BigDecimal overdraftFee;
}
 
@Entity(name = "CreditAccount")
public static class CreditAccount extends Account {
 
    private BigDecimal creditLimit;
}

Immutable

Hibernate skips any updates if the @Immutable has been used.
@Entity(name = "Batch")
public static class Batch {

    @Id
    private Long id;

    private String name;

    @OneToMany(cascade = CascadeType.ALL)
    @Immutable
    private List<Event> events = new ArrayList<>( );

    //Getters and setters are omitted for brevity

}

@Entity(name = "Event")
@Immutable
public static class Event {

    @Id
    private Long id;

    private Date createdOn;

    private String message;

    //Getters and setters are omitted for brevity

}