# Vererbung

Polymorphismus entsteht, wenn einem generellen Typ (Vehicle) spezialisiertere Typen untergeordnet sind (Car, Bicycle). Diese Typen besitzen dann die Properties des Parents, können aber auch eigene Properties mitbringen. JPA kennt drei verschiedene Strategien, dies in der Datenbank abzubilden:

  • Single Table: Hierbei wird nur eine Tabelle erzeugt, welche die Gesamtmenge aller Spalten über alle Child-Typen sowie den Parent-Typ enthält, zur Unterscheidung wird automatisch eine Extraspalte ("DTYPE") eingefügt, in welcher der genaue Typ steht
    • ✔ am performantesten, da alle Daten in derselben Tabelle liegen
    • ➖ bei vielen Child-Typen entstehen viele Spalten, die meistens leer sind
    • ❌ gleichnamige Spalten können keine unterschiedlichen Typen/Definitionen haben
    • ❌ es können in den Child-Typen keine NON-NULLABLE Spalten verwendet werden, da die anderen Typen dies nicht erfüllen würden
  • Joined: In der Haupttabelle werden nur Spalten für die Felder des Parents angelegt, alle Children bekommen eine extra Tabelle
    • ✔ spart unnötig leere Spalten
    • ✔ hält die Tabellen klein
    • ➖ etwas unperformanter, da immer JOINs gemacht werden müssen
    • ❌ bei polymorphen Abfragen müssen so viele JOINs gemacht werden, wie es Child-Typen gibt
  • Table Per Class: für jedes Entity (egal ob Parent oder Child) wird eine extra Tabelle angelegt, die Tabellen der Children enthalten dabei alle Spalten (auch die des Parents)
    • diese Strategie ist @MappedSuperclass sehr ähnlich, der Unterschied ist, dass dort die Parent-Klasse keine Entity sein kann
    • ❌: lieber eine der beiden anderen Strategien verwenden

Es ist abzuwägen, welche Strategie benutzt werden soll (vielleicht reicht auch @MappedSuperclass, falls es keine Relationen gibt). Diese wird dann bei der Parent-Klasse mittels @Inheritance festgelegt (wobei Single Table der Standard ist).

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
open class ParentEntity(
  // ...
) {
  // ...
}

Zu beachten ist, dass keine data class benutzt werden kann, da diese keine Vererbung unterstützt. Daher werden normale Klassen verwendet. Diese sind standardmäßig final in Kotlin, müssen also mit open gekennzeichnet werden. Ebenso müssen alle Properties der Parent-Entity mit open var bzw. open val deklariert werden. Falls es die Parent-Entity selbst nicht als Instanz geben kann, kann sie auch als abstract class angelegt werden.

Die Child-Entities werden ebenso als normale, aber abgeleitete, Klasse angelegt.

@Entity
class ChildEntity(
  // ...
): ParentEntity() {
  // ...
}