+ All Categories
Home > Documents > Erbschafts-Angelegenheiten Persistenz und Ver- erbung in ... fileten Blick sehr ähnlich wie SQL und...

Erbschafts-Angelegenheiten Persistenz und Ver- erbung in ... fileten Blick sehr ähnlich wie SQL und...

Date post: 09-Apr-2019
Category:
Upload: vukiet
View: 218 times
Download: 0 times
Share this document with a friend
3
www.javaspektrum.de 53 FACHTHEMA Erbschafts-Angelegenheiten Persistenz und Ver- erbung in Hibernate – Teil 2: Persistenz und Polymorphismus Dirk Mascher Mit Hibernate 3 steht eine in vielen Projekten erfolgreich eingesetzte ORM-Technologie zur Verfügung. Im ersten Teil wurde anhand eines ein- fachen Domänen-Modells aufgezeigt, wie sich Vererbungshierarchien mit Hilfe von Hibernate auf ein relationales Schema abbilden lassen. Dieser abschließende zweite Teil zeigt, dass objektrelationale Abbildungen keinen Bruch in der Objektorientierung bedeuten müssen und geht auf verschie- dene Aspekte von Polymorphismus im Zusammenhang mit Persistenz ein. E Im ersten Teil dieses zweiteiligen Artikels [Ma06] wurden die prinzipiellen Möglichkeiten aufgezeigt wie sich Vererbungs- hierarchien auf ein relationales Schema abbilden lassen. Anhand eines einfachen Domänen-Modells, das im Folgenden noch ein- mal kurz vorgestellt wird, wurden diese Strategien bzw. Muster mit den in Hibernate 3 vorgesehenen Mitteln umgesetzt. In diesem Teil des Artikels werden die Hibernate-Mappings um eine polymorphe Assoziation ergänzt. Außerdem wird er- läutert, was polymorphe Abfragen sind, wie diese in der Hiber- nate-Abfragesprache HQL formuliert und über die Hibernate API abgesetzt werden. In diesem Zusammenhang wird auch auf die Hibernate-Console als nützliches Tool für das Prototy- ping von HQL-Abfragen eingegangen. Domänen-Modell Online-Shop Als Grundlage für die Beispiele in diesem und im ersten Teil des Artikels dient das stark vereinfachte Domänen-Modell eines fiktiven Online-Shops. In dem Online-Shop gibt es regis- trierte Kunden. Jeder Kunde kann mehrere Zahlungsinforma- tionen hinterlegen und bei Bezahlvorgängen eine davon aus- wählen. Eine Zahlungsinformation ist dabei erst einmal etwas Abstraktes. Konkrete Ausprägungen können z. B. Kreditkarten oder Bankverbindungen sein. Es ergibt sich damit das in Abbil- dung 1 dargestellte Modell. Polymorphe Assoziationen Im ersten Teil dieses Artikels wurden die Hibernate-Map- pings für die Abbildung der PaymentInfo-Vererbungshierar- chie mit den drei möglichen Strategien vorgestellt. Was für die vollständige Abbildung des vereinfachten Domänen-Mo- dells noch fehlt, ist das Hibernate-Mapping für die Customer- Klasse (s. Listing 1). Interessant ist hier vor allem die Definition der „1”-Seite der bidirektionalen, polymorphen „1:n”-Assoziation zwischen Cus- tomer- und PaymentInfo-Objekten. Als Ziel-Datentyp für die „n“- Seite der Assoziation ist die abstrakte Basisklasse PaymentInfo an- gegeben. Das Ergebnis (genauer gesagt das Ergebnis-Set), das Hibernate bei einem Aufruf der getPaymentInfos-Methode von einem Customer-Objekt zurückliefert, ist also polymorph, d. h. es kann in unserem Beispiel Objekte der konkreten Typen Credit- Card oder BankAccount beinhalten. Mit Java 5 sieht der Zugriff auf das Set mit den assoziierten PaymentInfo-Objekten eines Customer-Objekts wie in Listing 2 ge- zeigt aus. Abb. 1: Domänen-Modell zum Beispiel Online-Shop <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="samples.hibernate.inheritance.model.Customer" table="CUSTOMER"> <id name="id" type="long" column="CUSTOMER_ID"> <generator class="native" /> </id> <property name="userName" column="USER_NAME" type="string" not-null="true" unique="true" /> <property name="firstName" column="FIRST_NAME" type="string" /> <property name="lastName" column="LAST_NAME" type="string" /> <set name="paymentInfos" cascade="all" lazy="true" inverse="true"> <key column="CUSTOMER_ID"/> <one-to-many class="samples.hibernate.inheritance.model.PaymentInfo"/> </set> </class> </hibernate-mapping> Listing 1: Customer.hbm.xml, Hibernate-Mapping für die Customer-Klasse
Transcript
Page 1: Erbschafts-Angelegenheiten Persistenz und Ver- erbung in ... fileten Blick sehr ähnlich wie SQL und wurde ursprünglich auf der Basis von EJB-QL definiert. Allerdings haben die Entwick-ler

www.javaspektrum.de 53

Fachthema

Erbschafts-Angelegenheiten

Persistenz und Ver- erbung in Hibernate – Teil 2: Persistenz und PolymorphismusDirk Mascher

Mit Hibernate 3 steht eine in vielen Projekten erfolgreich eingesetzte ORM-Technologie zur Verfügung. Im ersten Teil wurde anhand eines ein-fachen Domänen-Modells aufgezeigt, wie sich Vererbungshierarchien mit Hilfe von Hibernate auf ein relationales Schema abbilden lassen. Dieser abschließende zweite Teil zeigt, dass objektrelationale Abbildungen keinen Bruch in der Objektorientierung bedeuten müssen und geht auf verschie-dene Aspekte von Polymorphismus im Zusammenhang mit Persistenz ein.

EIm ersten Teil dieses zweiteiligen Artikels [Ma06] wurden die prinzipiellen Möglichkeiten aufgezeigt wie sich Vererbungs-

hierarchien auf ein relationales Schema abbilden lassen. Anhand eines einfachen Domänen-Modells, das im Folgenden noch ein-mal kurz vorgestellt wird, wurden diese Strategien bzw. Muster mit den in Hibernate 3 vorgesehenen Mitteln umgesetzt.

In diesem Teil des Artikels werden die Hibernate-Mappings um eine polymorphe Assoziation ergänzt. Außerdem wird er-läutert, was polymorphe Abfragen sind, wie diese in der Hiber-nate-Abfragesprache HQL formuliert und über die Hibernate API abgesetzt werden. In diesem Zusammenhang wird auch auf die Hibernate-Console als nützliches Tool für das Prototy-ping von HQL-Abfragen eingegangen.

Domänen-Modell Online-Shop

Als Grundlage für die Beispiele in diesem und im ersten Teil des Artikels dient das stark vereinfachte Domänen-Modell eines fiktiven Online-Shops. In dem Online-Shop gibt es regis-trierte Kunden. Jeder Kunde kann mehrere Zahlungsinforma-tionen hinterlegen und bei Bezahlvorgängen eine davon aus-wählen. Eine Zahlungsinformation ist dabei erst einmal etwas Abstraktes. Konkrete Ausprägungen können z. B. Kreditkarten oder Bankverbindungen sein. Es ergibt sich damit das in Abbil-dung 1 dargestellte Modell.

Polymorphe Assoziationen

Im ersten Teil dieses Artikels wurden die Hibernate-Map-pings für die Abbildung der PaymentInfo-Vererbungshierar-chie mit den drei möglichen Strategien vorgestellt. Was für die vollständige Abbildung des vereinfachten Domänen-Mo-dells noch fehlt, ist das Hibernate-Mapping für die Customer-Klasse (s. Listing 1).

Interessant ist hier vor allem die Definition der „1”-Seite der bidirektionalen, polymorphen „1:n”-Assoziation zwischen Cus-tomer- und PaymentInfo-Objekten. Als Ziel-Datentyp für die „n“-Seite der Assoziation ist die abstrakte Basisklasse PaymentInfo an-gegeben. Das Ergebnis (genauer gesagt das Ergebnis-Set), das Hibernate bei einem Aufruf der getPaymentInfos-Methode von einem Customer-Objekt zurückliefert, ist also polymorph, d. h. es kann in unserem Beispiel Objekte der konkreten Typen Credit-Card oder BankAccount beinhalten.

Mit Java 5 sieht der Zugriff auf das Set mit den assoziierten PaymentInfo-Objekten eines Customer-Objekts wie in Listing 2 ge-zeigt aus.

Abb. 1: Domänen-Modell zum Beispiel Online-Shop

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping

PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

<class name="samples.hibernate.inheritance.model.Customer"

table="CUSTOMER">

<id name="id" type="long" column="CUSTOMER_ID">

<generator class="native" />

</id>

<property name="userName" column="USER_NAME" type="string"

not-null="true" unique="true" />

<property name="firstName" column="FIRST_NAME" type="string" />

<property name="lastName" column="LAST_NAME" type="string" />

<set name="paymentInfos" cascade="all"

lazy="true" inverse="true">

<key column="CUSTOMER_ID"/>

<one-to-many

class="samples.hibernate.inheritance.model.PaymentInfo"/>

</set>

</class>

</hibernate-mapping>

Listing 1: Customer.hbm.xml, Hibernate-Mapping für die Customer-Klasse

Page 2: Erbschafts-Angelegenheiten Persistenz und Ver- erbung in ... fileten Blick sehr ähnlich wie SQL und wurde ursprünglich auf der Basis von EJB-QL definiert. Allerdings haben die Entwick-ler

JavaSPEKTRUM 4/200654

Fachthema

Polymorphe Abfragen

Polymorphe Assoziationen bilden die Basis, um mit der Hiber-nate-Abfragesprache HQL (Hibernate Query Language) poly-morphe Abfragen formulieren zu können. HQL ist auf den ers-ten Blick sehr ähnlich wie SQL und wurde ursprünglich auf der Basis von EJB-QL definiert. Allerdings haben die Entwick-ler von Hibernate viele Unzulänglichkeiten von EJB-QL (wir sprechen hier von der EJB-Spezifikation 2.x) behoben, syntak-tisch überflüssige Elemente entfernt und die Sprache um eine konsequente Unterstützung für Objektorientierung inklusive Polymorphismus erweitert.

Wie in EJB-QL gibt man in HQL in der From-Klausel nicht den Namen einer Datenbank-Tabelle an. In HQL wird statt-dessen der Name einer abgebildeten Java-Klasse angegeben. Im Gegensatz zu EJB-QL kann man hier jedoch auch Basis-klassen oder sogar Java-Interfaces angeben. Eine einfache, polymorphe HQL-Abfrage wäre in unserem Beispiel select p from PaymentInfo p, was äquivalent ist zu der etwas kom-pakteren Schreibweise from PaymentInfo. Als Ergebnis bekommt man alle in der Datenbank gespeicherten PaymentInfo-Objekte, d. h. in unserem Beispiel sowohl CreditCard- als auch BankAc-count-Objekte.

Sehr eindrucksvoll demonstriert auch die einfache Abfrage from java.lang.Object die Unterstützung von Polymorphismus in HQL. Wenn auch nicht wirklich zu empfehlen, könnten mit dieser Abfrage auf einfachste Weise alle persistierten Objekte einer Anwendung aufgelistet werden.

Implizite Joins über polymorphe Assoziationen

Ein weiteres interessantes Feature, das HQL bietet, sind impli-zite Joins. Diese erlauben es, extrem kompakte Abfragen über mehrere abgebildete Klassen (bzw. Tabellen) zu formulieren, ohne dass auf den ersten Blick erkennbar ist, dass diese auf SQL-Ebene tatsächlich in Join-Operationen übersetzt werden müssen. Einzige Voraussetzung für implizite Joins sind abge-bildete Assoziationen, die auch polymorph sein können.

Mit der in Listing 3 als Named-Query dargestellten, sehr kompakten HQL-Abfrage ist es beispielsweise möglich, alle Customer-Objekte aufzulisten, für die als Zahlungsinformation

mindestens ein CreditCard-Objekt regis-triert wurde. Im Java-Code könnte die Ausführung dieses Named-Queries dann wie in Listing 4 gezeigt ausse-hen. Natürlich sollte dieser Code am besten in einer Datenzugriffsobjekt-klasse (DAO) gekapselt werden.

Hibernate-Console

Sehr eindrucksvoll lassen sich HQL-Abfragen interaktiv in der Hibernate-Console ausführen. Die Hibernate-Console (für Hibernate 3) ist Bestand-teil des ebenfalls frei verfügbaren Eclipse-Plug-Ins „Hibernate-Tools“ und eignet sich sehr gut, um HQL-Ab-fragen zu testen, bevor sie beispiels-weise als Named-Queries in Mapping-Dokumenten hinterlegt werden. Ab-bildung 2 zeigt den Aufruf einer po-lymorphen HQL-Abfrage mit einem impliziten Join in der Where-Klausel und die Darstellung des polymorphen Ergebnisses in der View „Hibernate Query Result“ der Hibernate-Console.

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping

PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

<class name="samples.hibernate.inheritance.model.Customer"

table="CUSTOMER">

...

</class>

<query name="customersWithCreditCards">

select cc.customer from CreditCard cc

</query>

</hibernate-mapping>

Listing 3: Definition des Named-Query „customersWithCreditCards"

...

Session session = ...; // initialisiertes Hibernate Session-Objekt

...

Query query = session.getNamedQuery("customersWithCreditCards");

List<Customer> customers = query.list();

for (Customer customer : customers) {

...

}

Listing 4: Aufruf des Named-Query „customersWithCreditCards"

...

Customer customer = ...; // Customer-Objekt wird z.B. über DAO geladen

...

Set<PaymentInfo> paymentInfos = customer.getPaymentInfos();

for(PaymentInfo paymentInfo : paymentInfos) {

// hier z.B. abstrakte oder überschriebene Methode aufrufen

}

Listing 2: Polymorpher Zugriff auf assoziierte PaymentInfo-Objekte

Abb. 2: Screenshot „Hibernate Console”, Perspektive des Eclipse-Plug-Ins „Hibernate-Tools”

Page 3: Erbschafts-Angelegenheiten Persistenz und Ver- erbung in ... fileten Blick sehr ähnlich wie SQL und wurde ursprünglich auf der Basis von EJB-QL definiert. Allerdings haben die Entwick-ler

JavaSPEKTRUM 4/2006

Fachthema

Dirk Mascher ist selbständiger Berater im Java- und J2EE-Umfeld. Er hat in den letzten Jahren viele größere J2EE-Projekte zum Erfolg geführt. Ein Schlüssel dieses Erfolgs lag u. a. darin, zu einzelnen, problematischen J2EE-Technologien Alternativen zu finden. Eine dieser Alternativen ist Hibernate, das Dirk Mascher bereits in mehreren Projekten erfolgreich einsetzen konnte. Neben seiner Projekttätigkeit hat Dirk Mascher in den letzten Jahren mehrere Seminare entwickelt, u. a. auch zu dem Thema Hibernate. Dirk Mascher ist zertifi-zierter JBoss Consultant. E-Mail: [email protected].

Generell anzumerken ist an dieser Stelle noch, dass eine polymorphe HQL-Abfrage unabhängig von der gewählten Strategie für die Abbildung der Vererbungshierarchie ist. Die Abfrage from PaymentInfo funktioniert also bei allen drei vor-gestellten Strategien (siehe [Ma06,Fow03]) gleich und würde (denselben Datenbestand vorausgesetzt) auch jeweils dasselbe Ergebnis liefern. Einziger Unterschied bestünde darin, dass Hi-bernate je nach gewählter Strategie andere (mehr oder weniger komplexe) SQL-Statements erzeugen würde. In der „Hibernate Dynamic Query Translator View“ der Hibernate-Console be-steht die Möglichkeit, sich die generierten SQL-Abfragen im jeweiligen Dialekt der Zieldatenbank direkt anzuschauen.

Fazit

Die Definition eines sauberen Domänen-Modells ist der Schlüssel für den Erfolg komplexer Enterprise-Anwendungen. Im Gegen-satz zu der (zum Zeitpunkt der Entstehung dieses Artikels noch aktuellen) EJB-Spezifikation 2.1 (genauer gesagt CMP 2.1) ist es mit Hibernate möglich, ein Domänen-Modell direkt auf die zu-grunde liegende Datenbank abzubilden. Hibernate unterstützt da-bei ab Version 3.0 alle drei prinzipiell möglichen Strategien für die Abbildung von Vererbungshierarchien, sodass man als Architekt je nach konkreten Anforderungen die „günstigste“ (in der Praxis gleichbedeutend mit „effizienteste“) Strategie auswählen kann.

Gerade die Hibernate Query Language HQL bietet ein sehr mächtiges Mittel, auch komplexe Anfragen kompakt zu for-mulieren. Die Wahl der Strategie für die Abbildung von Verer-bungshierarchien ist hierbei völlig transparent. Hibernate sorgt dafür, dass HQL-Abfragen in das jeweils best mögliche SQL-Statement im jeweiligen SQL-Dialekt der zugrunde liegenden relationalen Datenbank transformiert werden.

Viele der Ideen von Hibernate sind in die Spezifikation von EJB 3.0 eingeflossen. Dies hat zur Folge, dass das Persistenz-Mo-dell, wie es im JSR-220 [JSR220] definiert ist, in vielen Bereichen große Ähnlichkeit mit dem Persistenz-Modell von Hibernate aufweist. Wer heute bereits erste praktische Erfahrungen mit EJB-3.0-Persistenz sammeln will, sollte einmal einen Blick auf

zwei Unterprojekte von Hibernate werfen: Hibernate EntityMan-ager und Hibernate Annotations. Hibernate EntityManager ist ein dünner Wrapper um den Kern von Hibernate 3, der zusammen mit Hibernate Annotations einen vollständigen, allein stehen-den EJB3 Persistence Provider implementiert. Mit dieser Kombi-nation hat man die Möglichkeit, erste praktische Erfahrungen mit dem Persistenz-Modell von EJB 3 zu sammeln, und dabei die Gewissheit, dass im Hintergrund eine über Jahre erprobte und zuverlässige Technologie die eigentliche Arbeit erledigt.

Literatur und Links

[Bet05] U. Bettag, Persistenz mit Hibernate, in: JavaSPEKTRUM, Sonderheft zur CeBit, 2005[Fow03] M. Fowler, Patterns of Enterprise Application Architec-ture, Addison-Wesley, 2003, http://www.martinfowler.com/eaaCatalog/

[HIB] Hibernate, http://www.hibernate.org/[JSR220] Java Specification Request 220: Enterprise JavaBeans 3.0, http://www.jcp.org/en/jsr/detail?id=220

[Ma06] D. Mascher, Persistenz und Vererbung in Hibernate – Teil 1, Prinzipien, in: JavaSPEKTRUM, 3/2006

www.javaspektrum.de 55


Recommended