Blog

Hibernate Komponente (Wertobjekt) Vererbungszuordnung

Priyanshu Goyal

Aktualisiert Oktober 23, 2025
3 Minuten

Das Mapping der Entitätsvererbung in Hibernate kann ganz einfach über eine der drei Strategien erfolgen und oft wird die Instanz der zu erstellenden Unterklasse durch den Wert der Diskriminatorspalte identifiziert (insbesondere im Fall einer Tabelle pro Klassenhierarchie). Für solche Zuordnungen gibt es in Hibernate bereits eine inhärente Unterstützung. Das ist gut, wenn wir für jede Zeile eine Unterklasse eines bestimmten Typs erstellen wollen, aber was ist, wenn wir für einen Wert einer Spalte innerhalb dieser Zeile eine Instanz einer bestimmten Klasse erstellen wollen. Also gewissermaßen eine Art Abbildung der Komponentenvererbung. Dies ist erforderlich, wenn ich ein Wertobjekt (Komponente) wirklich nicht in eine Entität umwandeln möchte, da dies bedeuten könnte, dass ich die Unterscheidung zwischen einer Komponente und einer Entität verliere. Eine vorläufige Lösung könnte darin bestehen, einen UserType zu verwenden, um eine Instanz eines solchen Objekts auf der Grundlage des in der Spalte gespeicherten Werts zu erstellen. Das Konzept der Diskriminatorspalte kann uns immer noch helfen. Lassen Sie uns anhand des folgenden Beispiels sehen, wie

Angenommen, wir haben einen Katalog mit Büchern, in dem jedes Buch eine Preisangabe hat, die von der Währung abhängt, in der das Buch ursprünglich veröffentlicht wurde. Jede Preisangabe wird durch eine separate Klasse modelliert, die eine Eigenschaft amount hat. Nehmen wir an, dass diese Klassen je nach Währung ein unterschiedliches Verhalten bei der Berechnung der Mehrwertsteuer und anderen Dingen haben (andernfalls können wir einfach eine Klasse erstellen und die Zuordnung über eine Komponente oder eins-zu-eins vornehmen). Der Büchertisch sieht also in etwa so aus [sql]CREATE TABLE BOOK ( ID NUMBER(19,0) NOT NULL, PRICE_SPEC_TYPE VARCHAR2(3) NOT NULL, PRICE_AMOUNT NUMBER(19,0) NOT NULL, ... );[/sql] Und die Buchklasse wie folgt [java]public class Book { private long id; private PriceSpecification priceSpecification; ... [/java] } Und eine der Preisangaben kann lauten [java]public class USDollarSpecification implement PriceSpecification { private long amount; public void setAmount(long amount) { this.amount = amount; } public long getMaximumRetailPrice() { } ... [/java] } Dies kann natürlich mit einem UserType abgebildet werden, aber um es sauberer zu machen, verwenden wir ein Enum. Ein Beispielcode für PriceSpecificationUserType sieht etwa so aus. [java]public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { String type = rs.getString(names[0]); long amount = rs.getLong(names[1]); PriceSpecificationType priceSpecType = priceSpecificationType.valueOf(type); PriceSpecification specification = priceSpecType.getNewInstance(); specification.setAmount(); return specification; } [/java] Hier erstellen wir eine Instanz einer Preisangabe aus dem Wert in der Spalte PRICE_SPEC_TYPE unter Verwendung einer Enum für Preisangabe-Typen. [java]public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index) throws HibernateException, SQLException { wenn (Wert == Null) { preparedStatement.setNull(index, Types.VARCHAR); preparedStatement.setNull(index + 1, Types.NUMERIC); } sonst { PriceSpecification priceSpecification = (PriceSpecification) value; String className = priceSpecification.getClass().getName(); PriceSpecificationType[] priceSpecTypes = PriceSpecificationType.values(); for (int i = 0; i < priceSpecTypes.length; i++) { PriceSpecificationType priceSpecType = priceSpecTypes[i]; if (priceSpecType.getClassName().equals(className)) { preparedStatement.setString(index, priceSpecType.name()); Pause; } } preparedStatement.setInt(index + 1, priceSpecification.getAmount()); } }[/java] In ähnlicher Weise legen wir die Preisangabe in PRICE_SPEC_TYPE fest, indem wir das Enum für Preisangabe-Typen verwenden. So sieht das Enum aus [java]public enum PriceSpecificationType { US_DOLLAR { public String getClassName() { return USDollarSpecification.class.getName(); } @Override public PriceSpecification getNewInstance() { return new USDollarSpecification(); } }, ... public abstract PriceSpecification getNewInstance(); public abstract String getClassName(); } [/java] Und schließlich sehen wir uns die Zuordnung an [xml] <class name="Buch" table="BOOK"

[/xml] Hibernate wird dies möglicherweise in einer der zukünftigen Versionen unterstützen (siehe Opensource.atlassian.com/projects/hibernate/browse/HHH-1152 ), aber im Moment müssen wir wohl mit diesem Workaround leben.

Verfasst von

Priyanshu Goyal

Contact

Let’s discuss how we can support your journey.