Komponenten-basierte Entwicklung Teil 13: Persistenz mit Hibernate I Komponenten – WS 2014/15 – Teil 13/Hibernate 18.12.14 1 Literatur [13-1] Müller, Bernd; Wehr, Harald: Java Persistence API 2. Hanser, 2012. [13-2] Beeger, Robert et al.: Hibernate. Persistenz in Java-Systemen mit Hibernate 3. dpunkt, 2006 [13-3] http://sourceforge.net/projects/hibernatesample/ [13-4] http://hibernate.org/ [13-5] http://mvnrepository.com/artifact/org.hibernate Wenn Sie beim Implementieren Probleme haben, benutzen Sie Google. Auf der Site www.stackoverflow.com sind fast alle Programmierprobleme mit Lösungen erläutert. Komponenten – WS 2014/15 – Teil 13/Hibernate 2 Was macht Hibernate • Hibernate realisiert die JPA-Schnittstelle in der Version 2.0. Siehe: http://de.wikipedia.org/wiki/Hibernate_(Framework) • JPA = Java Persistence API Siehe: http://de.wikipedia.org/wiki/Java_Persistence_API • Hibernate orientiert sich der Struktur und Benennung der Klassen, nicht an der der unterliegenden Tabellen in der Datenbank. • Die Fehlermeldungen sind meist nichts sagend, irreführend oder werden erst gar nicht ausgegeben. In diesem Teil wird die XML-basierte Variante beschrieben; es gibt noch die mit Annotationen. Komponenten – WS 2014/15 – Teil 13/Hibernate 3 Maven und Hibernate <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>4.3.7.Final</version> </dependency> In diesem Foliensatz wird nur der Core benutzt. Komponenten – WS 2014/15 – Teil 13/Hibernate 4 Das Indische Restaurant – Die Objekte Customer Set 1:N Place Explanation 1:1 List N:M Menu List • • Es wird ein indisches Restaurant modelliert. Gäste (Customers) sitzen an Tischen (Places) und bestellen (Order) • Gerichte aus der Karte (Menu). Da die Gerichte scharf oder auch vegetarisch sein können, gibt es zu jedem Gericht eine Erläuterung (Explanation). • Es werden alle Arten von Beziehungen benutzt, die durch PointerStrukturen realisiert werden. Die N:M-Beziehung wird durch gegenseitige Referenzierung erreicht. • Komponenten – WS 2014/15 – Teil 13/Hibernate 5 Die JavaBeans I public class Customer { private int id; private String firstName; private String lastName; private boolean vegetarian; … getter/setter … } Customer Explanation List Set Place Menu Realisierung der 1:N-Relation public class Place { private int id; private int number; private int seats; private Date date; private Set customers= new HashSet(); private List orders= new ArrayList(); … getter/setter … } Komponenten – WS 2014/15 – Teil 13/Hibernate Erste Hälfte der N:M-Relation 6 Die JavaBeans II Customer public class Menu { private int ide; private String name; List Set private double price; private List tables= new ArrayList(); Place private Explanation e_id; … getter/setter … } Zweite Hälfte der Explanation Menu N:M-Relation public class Explanation { private int id; private String text; private Menu menu; … getter/setter … } Komponenten – WS 2014/15 – Teil 13/Hibernate Realisierung der 1:1-Relation Es müssen also alle Zeiger deklariert sein. 7 Das Indische Restaurant – Die Tabellen Customer Explanation N:1/0 1:1 N:M Places Menu Ordered Für eine N:M-Beziehung ist eine weitere Tabelle erforderlich. Komponenten – WS 2014/15 – Teil 13/Hibernate • • • Statt Place (für Tisch) müsste es eigentlich Table heißen, Statt Ordered (für Bestellung) eigentlich order heißen. Da aber Table und Order in SQL Schlüsselworte sind und Hibernate mit den Back-Ticks diese Bedeutung nicht aufhebt, mussten hier die Tabellen umbenannt werden. 8 Die Tabellen I CREATE TABLE `indianrestaurant`.`customer` ( `id` INT NOT NULL AUTO_INCREMENT, `FirstName` VARCHAR(45) NULL, `LastName` VARCHAR(45) NULL, `Vegetarian` BIT NOT NULL, `id_table` INT, PRIMARY KEY (`id`)); Realisierung der 1:N-Relation Customer Explanation Places Menu Ordered CREATE TABLE `indianrestaurant`.`place` ( `id` INT NOT NULL AUTO_INCREMENT, `Num` INT NOT NULL, Tabelle ist frei `Seats` INT NULL DEFAULT 1, von Verwaltung `clock` TIMESTAMP, PRIMARY KEY (`id`)); Komponenten – WS 2014/15 – Teil 13/Hibernate 9 Die Tabellen II CREATE TABLE `indianrestaurant`.`explanation`( `id_e` INT NOT NULL AUTO_INCREMENT, `menu` INT, `Text` VARCHAR(255) NOT NULL, PRIMARY KEY (`id_e`)); Realisierung der 1:1-Relation Customer Explanation Places Menu Ordered CREATE TABLE `indianrestaurant`.`menu` ( `id_e` INT NOT NULL AUTO_INCREMENT, `Name` VARCHAR(45) NOT NULL, `Price` FLOAT NOT NULL, PRIMARY KEY (`id_e`), CONSTRAINT `menu_explanation` FOREIGN KEY (`id_e`) REFERENCES `explanation` (`id_e`)); Komponenten – WS 2014/15 – Teil 13/Hibernate 10 Die Tabellen III Customer Explanation Places Menu CREATE TABLE `indianrestaurant`.`ordered` ( `id_place` INT, `id_menu` INT, `ind` INT Gegenseitige ); Verbindung der N:M-Relation Ordered Attribut für Reihenfolge (List) Hibernat erstellt nicht automatisch die Tabellen; diese müssen von Hand samt Datenbank erstellt werden. Komponenten – WS 2014/15 – Teil 13/Hibernate 11 Hibernate Konfiguration I - hibernate.cfg.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> … … … </session-factory> </hibernate-configuration> Komponenten – WS 2014/15 – Teil 13/Hibernate Hier kommt die Konfiguration hinein Immer gleich bleibender Kopf 12 Hibernate Konfiguration I - hibernate.cfg.xml <property name="hibernate.connection.driver_class"> com.mysql.jdbc.Driver JDBC-Treiber </property> <property name="hibernate.connection.url"> Datenbank-Name jdbc:mysql://localhost/indianrestaurant </property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection password"></property> <property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property> <property name="hibernate.jdbc.batch_size">0</property> <property name="transaction.factory_class"> org.hibernate.transaction.JDBCTransactionFactory </property> Datenbank-Typ <property name="show_sql">true</property> Gibt die SQLStatements aus – Debugging! Komponenten – WS 2014/15 – Teil 13/Hibernate 13 Hibernate Konfiguration II - hibernate.cfg.xml <mapping <mapping <mapping <mapping • resource="Place.hbm.xml"/> resource="Customer.hbm.xml"/> resource="Menu.hbm.xml"/> resource="Explanation.hbm.xml"/> Verweise auf Tabellendefinitionen Es ist üblich für jede Klasse eine eigene Tabellendefinitionsdatei anzulegen. Weitere Möglichkeiten <property name="format_sql">true</property> <property name="use_sql_comments">true</property> • • format_sql formatiert die ausgegebenen SQL-Statements etwas use_sql_comments sorgt dafür, dass der Sinn der SQL-Statements kommentiert wird. Komponenten – WS 2014/15 – Teil 13/Hibernate 14 Hibernate Konfiguration III - log4j log4j.rootCategory=INFO, A1 log4j.appender.A1=org.apache.log4j.ConsoleAppender log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=%-5p - %m%n • Es wird log4j zur Ausgabe im Konsolenfenster benutzt. • Dies ist hier ein erster Vorschlag. • Diese Werte kommen in die Datei log4j.properties Komponenten – WS 2014/15 – Teil 13/Hibernate 15 Anordnung der Dateien bei netbeans Komponenten – WS 2014/15 – Teil 13/Hibernate 16 Hibernate Konfiguration IV – Customer.hbm.xml <?xml version="1.0" encoding="UTF-8"?> Kopf <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="de.htw_berlin.f4.kbe.hibernate.Customer" table="customer"> Tabelle … … … </class> Abbildungen </hibernate-mapping> Klasse Nach dieser Struktur sind alle Mapping-Dateien aufgebaut. Im folgenden wird der Rahmen nicht mehr dargestellt. Komponenten – WS 2014/15 – Teil 13/Hibernate 17 Hibernate Konfiguration V – Customer.hbm.xml <id name="id" column="id" type="integer"> <generator class="native"/> </id> <property name="firstName" type="string" Definition des Schlüssels column="FirstName" not-null="true"/> <property name="lastName" type="string" column="LastName" not-null="true"/> <property name="vegetarian" type="boolean" column="Vegetarian"/> Struktur: Name – Hibernate-Type - Spalte class="native" bedeutet, dass die Datenbank-internen Verfahren zur Generierung der Schlüssel benutzt werden, hier: auto_increment Komponenten – WS 2014/15 – Teil 13/Hibernate 18 Hibernate Konfiguration VI – Place.hbm.xml <id column="id" name="id" type="integer"> Wie bei <generator class="native"/> Customer </id> <property name="number" type="integer" column="num" not-null="true"/> <property name="seats" type="integer" column="seats"/> <property name="date" type="timestamp" column="clock" not-null="true"/> <list name="orders" table="ordered" lazy="true"> N:M-Relation <key column="id_place"/> <list-index column="ind"/> <many-to-many class="de.htw_berlin.f4.kbe.hibernate.Menu" column="id_menu"/> </list> <set name="customers" lazy="true"> 1:N-Relation <key column="id_table"/> <one-to-many class="de.htw_berlin.f4.kbe.hibernate.Customer"/> </set> Komponenten – WS 2014/15 – Teil 13/Hibernate 19 Bemerkungen I <list name="orders" table="ordered" lazy="true"> <key column="id_place"/> <list-index column="ind"/> <many-to-many class="de.htw_berlin.f4.kbe.hibernate.Menu" column="id_menu"/> </list> • key column="id_place" gibt in der Tabelle ordered den Verweis auf sich selbst an. • list-index column="ind" definiert das Attribut für die Reihenfolge in der Liste • many-to-many class=ABC column=DEF gibt die N:M-Beziehung mit Verweis auf die andere Klasse (ABC) sowie das Attribut von der Klasse ABC an. • lazy="true" bedeutet, dass nur dann aus der Datenbank gelesen wird, wenn es nötig ist, also zum spätesten Zeitpunkt. Komponenten – WS 2014/15 – Teil 13/Hibernate 20 Bemerkungen II <set name="customers" lazy="true"> <key column="id_table"/> <one-to-many class="de.htw_berlin.f4.kbe.hibernate.Customer"/> </set> • key column="id_table" definiert den Namen des Attributs in der Tabelle für den Customer. • <one-to-many class="...Customer"> legt den Verweis auf die andere Tabelle mit dem Attribut key column fest. • lazy="true" bedeutet, dass nur dann aus der Datenbank gelesen wird, wenn es nötig ist, also zum spätesten Zeitpunkt. Komponenten – WS 2014/15 – Teil 13/Hibernate 21 Hibernate Konfiguration VII – Menu.hbm.xml <id name="id" type="integer"> <column name="id_e" /> <generator class="foreign"> Index als <param name="property">e_id</param> Fremdschlüssel </generator> </id> <property name="name" type="string" column="Name" not-null="true"/> <property name="price" type="double" column="Price" not-null="true"/> <list name="tables" table="ordered" lazy="true" inverse="true"> <key column="id_menu"/> <list-index column="ind"/> <many-to-many class="de.htw_berlin.f4.kbe.hibernate.Place" column="id_place"/> </list> <one-to-one name="e_id" class="de.htw_berlin.f4.kbe.hibernate.Explanation" constrained="true" /> 1:1-Relation Komponenten – WS 2014/15 – Teil 13/Hibernate 22 Bemerkungen I <list name="tables" table="ordered" lazy="true" inverse="true"> <key column="id_menu"/> <list-index column="ind"/> <many-to-many class="de.htw_berlin.f4.kbe.hibernate.Place" column="id_place"/> </list> Die N:M-Beziehung nun gespiegelt. Unten noch einmal die Konfiguration von Place <list name="orders" table="ordered" lazy="true"> <key column="id_place"/> <list-index column="ind"/> <many-to-many class="de.htw_berlin.f4.kbe.hibernate.Menu" column="id_menu"/> </list> Komponenten – WS 2014/15 – Teil 13/Hibernate 23 Bemerkungen II • Wird auf der Ebene der Tabellen eine Beziehung zwischen zwei Klassen realisiert, so wird in eine der beiden Tabellen ein zusätzliches Attribut eingefügt, das nicht zum Modell gehört. • Dieses Attribut erscheint auch nicht im UML-Diagramm. • Dieses Attribut wird auch Join-Spalte genannt. • Die Tabelle mit der Join-Spalte heißt Eigentümer der Beziehung, die andere Tabelle heißt dann invers. • Daher muss eine der betroffenen Tabellen inverse="true" haben. • Hier betrifft es eine birektionale Beziehung; daher ist es egal, welche die Eigentümer- und welche in inverse Tabelle ist. Komponenten – WS 2014/15 – Teil 13/Hibernate 24 Hibernate Konfiguration VIII – Explanation.hbm.xml <id name="id" type="integer"> <column name="e_id"/> <generator class="native"/> </id> <one-to-one name="menu" class="de.htw_berlin.f4.kbe.hibernate.Menu" cascade="save-update"/> <property name="text" type="string" column="Text" not-null="true"/> • cascade="save-update" bedeutet, dass Änderungen an die Tabelle für die Klasse Menu weiter gegeben werden. Komponenten – WS 2014/15 – Teil 13/Hibernate 25 Das Hauptprogramm I public class App { private SessionFactory sessionFactory; private ServiceRegistry serviceRegistry; private void prologue() { try { Configuration config= new Configuration().configure(); serviceRegistry= new StandardServiceRegistryBuilder() .applySettings(config.getProperties()).build(); sessionFactory= config.buildSessionFactory(serviceRegistry); SessionFrame.setFactory(sessionFactory); } catch( HibernateException ex ) { ex.printStackTrace(); throw new RuntimeException(ex.getMessage()); } } private void epilogue() { StandardServiceRegistryBuilder.destroy(serviceRegistry); } Komponenten – WS 2014/15 – Teil 13/Hibernate 26 Bemerkungen • prologue() baut den Hibernate-Kontext auf. Es wird eine SessionFactory generiert, die während des ganzen Programmlaufs benutzt wird. • epilogue() beendet den Hibernate-Kontext. Ohne diese Routine verbleibt • für jeden Programmlauf ein wartender Thread. SessionFrame.setFactory(sessionFactory) setzt die Factory in eine andere Klasse, die später erklärt wird. Komponenten – WS 2014/15 – Teil 13/Hibernate 27 Das Hauptprogramm II - main public static void main( String[] args ) { App me= new App(); me.prologue(); try { me.runner(); } catch (RuntimeException ex) { ex.getStackTrace(); } finally { me.epilogue(); } } • • Hiermit wird sichergestellt, dass in jedem Falle epilogue() aufgerufen wird. Per Konvention werden immer RuntimeException geworfen. • • Der Stacktrace ist für das Suchen nach Fehlermeldungen wichtig. Runner() ist das „eigentliche“ Programm. Komponenten – WS 2014/15 – Teil 13/Hibernate 28 Das Hauptprogramm III - runner Customers custer= new Customers(); custer.deleteAll(); custer.load(); custer.show(); Menues offer= new Menues(); offer.load(); offer.show(); Places tabs= new Places(); tabs.load(); tabs.show(); Die rot gekennzeichneten Klassen sind Hilfsklassen zur Benutzung der Beans. Komponenten – WS 2014/15 – Teil 13/Hibernate custer.sitAtTable(1,"Herbert"); custer.sitAtTable(1,"Hildegard"); custer.sitAtTable(2,"Daniel"); custer.sitAtTable(3,"Jana"); Orders ords= new Orders(); ords.order(1,"Malai Kofta"); ords.order(1,"Malai Kofta"); ords.order(2,"Mattar Paneer"); ords.order(3,"Dinkelkernotto"); 29 Klasse Customers I Das ist eine innere (lokale) Klasse. public void load() { class doThis implements DoHibernate { @Override public void execute(Session session) { session.save(new Customer("Herbert","Doener",true)); session.save(new Customer("Hildegard","Momms",false)); session.save(new Customer("Daniel","Maier",true)); session.save(new Customer("Jana","Moires",true)); } } SessionFrame.doIt(new doThis()); } • Die load()-Funktionen füllen initial die am Anfang leeren DatenbankTabellen. save() schreibt am Ende der Transaktion das Objekt in die Datenbank. • Alle Funktionen von Hibernate können Exceptions werfen, so dass ein trycatch-Rahmen um den eigentlichen Code immer wieder geschrieben werden muss (Boilerplate und DRY). • Hier ist der Rahmen in eine einzige Klasse ausgelagert. Komponenten – WS 2014/15 – Teil 13/Hibernate 30 Klasse SessionFrame I public class SessionFrame { private static SessionFactory sessionFactory; public static void setFactory(SessionFactory factory) { sessionFactory= factory; } Das ist nun der Beginn der Klasse, die den Rahmen realisiert. Unten steht das Interface für die Füllung des Rahmens. public interface DoHibernate { public void execute(Session session); } Komponenten – WS 2014/15 – Teil 13/Hibernate 31 Klasse SessionFrame II public static void doIt(DoHibernate obj) { 1.Teil des Session session= null; Transaction tx = null; Rahmens try { session= sessionFactory.openSession(); tx= session.beginTransaction(); Das ist der obj.execute(session); eigentliche tx.commit(); Teil } catch( HibernateException ex ) { ex.getStackTrace(); if(tx!= null) { try { tx.rollback(); } catch(HibernateException exRollBack) {} } throw new RuntimeException(ex.getMessage()) ; } finally { try { if(session!=null) { session.close();} 2.Teil des } catch(Exception exClose) {} Rahmens }}} Komponenten – WS 2014/15 – Teil 13/Hibernate 32 Klasse Customers II public void deleteAll() { HQL class doThis implements DoHibernate { @Override public void execute(Session session) { String hqlDelete= "delete Customer"; int deletedEntities= session.createQuery(hqlDelete) .executeUpdate(); } } SessionFrame.doIt(new doThis()); } • • Das ist nun der Code zum Löschen aller Objekte (einer Tabelle). Es wird die HQL, die Hibernate Query Language, benutzt. • • Sie ist dem SQL sehr ähnlich, operiert aber auf Objekten. Das Ganze läuft wie der gerade vorgestellte Teil im Rahmen von SessionFrame. • Die Operation zum Ausführen von HQL heißt executeUpdate(). Komponenten – WS 2014/15 – Teil 13/Hibernate 33 Klasse Customers III public void show() { Konvertierung HQL class doThis implements DoHibernate { zu einer Liste @Override public void execute(Session session) { System.out.println("Kunden:"); for (Object elem : session.createQuery("from Customer").list()) { Customer custer= (Customer) elem; System.out.println("Name: "+custer.getFirstName()+" "+ custer.getLastName()+" veggie: "+custer.getvegetarian()); } } } SessionFrame.doIt(new doThis()); } • • • Hier werden alle Objekte (einer Tabelle) vom Typ Customer selektiert. Dann werden die selektierten Objekte in eine List gebracht und in der Foreach-Schleife ausgewertet. Customer hat keine Referenzen auf andere Objekte, wenn die referenzierten Objekte auch gelesen werden sollen, ist dazu ein Join in HQL erforderlich. Komponenten – WS 2014/15 – Teil 13/Hibernate 34 Klasse Places public void load() { class doThis implements DoHibernate { @Override public void execute(Session session) { session.save(new Place(1,2, new Date())); session.save(new Place(2,4, new Date())); session.save(new Place(3,4, new Date())); session.save(new Place(4,1, new Date())); } } SessionFrame.doIt(new doThis()); } • Die load()-Funktionen füllen initial die am Anfang leeren Datenbank-Tabellen. save() schreibt am Ende der Transaktion das Objekt in die Datenbank. • Die show()-Funktion ist analog zu der der Klasse Customer aufgebaut. Komponenten – WS 2014/15 – Teil 13/Hibernate 35 Klasse Menues public void load() { class doThis implements DoHibernate { private Menu build(String name, double price, String explain) { Explanation expl= new Explanation(explain); Menu meal= new Menu(name,price,expl); expl.setMenu(meal); Etwas lustlose return meal; Erläuterungen } @Override public void execute(Session session) { session.save(build("Dinkelkernotto", 12.5, "A")); session.save(build("Sambhara", 7.5, "B")); session.save(build("Korianderchutney", 3.7, "C")); session.save(build("Mattar Paneer", 5.0, "D")); session.save(build("Methi Chicken Curry", 6.5, "E")); session.save(build("Biriyani", 5.0, "F")); session.save(build("Malai Kofta", 3.6, "G")); } } SessionFrame.doIt(new doThis());} • Hier werden die Objekte Menu und Explanation (1:1-Relation) in ihre Tabellen gebracht (Achtung! SQL-Constraint-Bedingung). Komponenten – WS 2014/15 – Teil 13/Hibernate 36 Noch einmal der runner() Customers custer= new Customers(); custer.deleteAll(); custer.load(); Erledigt custer.show(); Menues offer= new Menues(); offer.load(); offer.show(); Places tabs= new Places(); tabs.load(); tabs.show(); Das kommt nun... custer.sitAtTable(1,"Herbert"); custer.sitAtTable(1,"Hildegard"); custer.sitAtTable(2,"Daniel"); custer.sitAtTable(3,"Jana"); Orders ords= new Orders(); ords.order(1,"Malai Kofta"); ords.order(1,"Malai Kofta"); ords.order(2,"Mattar Paneer"); ords.order(3,"Dinkelkernotto"); Komponenten – WS 2014/15 – Teil 13/Hibernate 37 Jemand setzt sich an einen Tisch I public void sitAtTable(int tableNumb, String name) { final int tableNumber= tableNumb; final String CustomerName= name; class doThis implements DoHibernate { private void build(...) {...} @Override public void execute(Session session) { build(session,tableNumber,CustomerName); } } SessionFrame.doIt(new doThis()); } • Hier wird wieder mit einer inneren Klasse gearbeitet, aber es müssen Parameter übergeben werden. • Globale Daten (Parameter z.B.) müssen zum Zugriff in inneren Klassen als final, also als Konstanten, benutzt werden. Daher werden die Parameter umkopiert. • Die build()-Rountine wird auf der nächsten Folie erläutert. Komponenten – WS 2014/15 – Teil 13/Hibernate 38 Jemand setzt sich an einen Tisch II String HQL1= "select place from Place as place where place.number=:numm"; String HQL2= "select customer from Customer as customer"+ " where customer.firstName=:name"; private void build(Session session, int tableNumber, String name) { Iterator itrTable = session.createQuery(HQL1) .setInteger("numm",tableNumber).iterate(); Iterator itrCustom= session.createQuery(HQL2) .setString("name",name).iterate(); if(itrTable.hasNext() && itrCustom.hasNext()) { Place table= (Place) itrTable.next(); Customer person= (Customer) itrCustom.next(); table.getCustomers().add(person); } else { throw new RuntimeException("Unknown table or customer"); }} • HQL1 und HQL2 sind zwei Selects mit einer where-Klausel. • :numm bzw. :name sind symbolische Namen wie bei den prepared Statements. Mit setInteger() und setString() werden sie gesetzt. Komponenten – WS 2014/15 – Teil 13/Hibernate 39 Bemerkungen session.createQuery(HQL1).setInteger("numm",tableNumber).iterate() In einem Stück wird der Parameter gesetzt, das Query ausgeführt und dessen Ergebnis zu einem Iterator umgewandelt (oben war es eine List). itrTable.hasNext() && itrCustom.hasNext() Hier wird entsprechend dem Iterator-Interface abgefragt, ob beide Objekte existieren. table.getCustomers().add(person); Und nun wird in das Set der Klasse Place über dessen Attribut Customers per add() eine Person eingefügt. Komponenten – WS 2014/15 – Teil 13/Hibernate 40 Nun wird etwas bestellt I public void order(int tableNum, String meal) { final int tableNumber= tableNum; final String mealName= meal; class doThis implements DoHibernate { private void build(...) { … } @Override public void execute(Session session) { build(session,tableNumber,mealName); } } SessionFrame.doIt(new doThis()); } • Hier wird wieder mit einer inneren Klasse gearbeitet, aber es müssen Parameter in final-Variablen kopiert übergeben werden. • Die build()-Rountine wird auf der nächsten Folie erläutert. Komponenten – WS 2014/15 – Teil 13/Hibernate 41 Nun wird etwas bestellt I String HQL1= "select place from Place as place where place.number=:numm"; String HQL2= "select menu from Menu as menu where menu.name=:meal"; private void build(Session session, int placeNumber, String mealName) { Iterator itrTable= session.createQuery(HQL1) .setInteger("numm", placeNumber).iterate(); Iterator itrMeal = session.createQuery(HQL2). .setString("meal",mealName).iterate(); if(itrTable.hasNext() && itrMeal.hasNext()) { Place table= (Place) itrTable.next(); Menu meal= (Menu) itrMeal.next(); table.getOrders().add(meal); meal.getTables().add(table); } else { throw new RuntimeException("Unknown place or meal"); }} • Das läuft nach demselben Schema ab: Es werden zwei Objekte per HQLSelect ausgewählt und... • gegenseitig in die jeweils andere Liste eingetragen. Komponenten – WS 2014/15 – Teil 13/Hibernate 42 Output (Auszug) I Dez 18, 2014 1:30:21 PM org.hibernate.annotations.c..... <clinit> INFO: HCANN000001: Hibernate Commons Annotations {4.0.5.Final} Dez 18, 2014 1:30:21 PM org.hibernate.Version logVersion INFO: HHH000412: Hibernate Core {4.3.7.Final} OK, keine Dez 18, 2014 1:30:21 PM org.hibernate.cfg.Environment <clinit> Properties INFO: HHH000206: hibernate.properties not found Dez 18, 2014 1:30:21 PM org.hibernate.cfg.Configuration configure INFO: HHH000043: Configuring from resource: /hibernate.cfg.xml OK, die Dez 18, 2014 1:30:21 PM org.hibernate.cfg.Configuration … Konfig-Datei INFO: HHH000040: Configuration resource: /hibernate.cfg.xml Dez 18, 2014 1:30:21 PM org.hibernate.cfg.Configuration addResource INFO: HHH000221: Reading mappings from resource: Place.hbm.xml Dez 18, 2014 1:30:21 PM org.hibernate.cfg.Configuration addResource INFO: HHH000221: Reading mappings from resource: Customer.hbm.xml Dez 18, 2014 1:30:21 PM org.hibernate.cfg.Configuration addResource INFO: HHH000221: Reading mappings from resource: Menu.hbm.xml Dez 18, 2014 1:30:21 PM org.hibernate.cfg.Configuration addResource INFO: HHH000221: Reading mappings from resource: Explanation.hbm.xml Dez 18, 2014 1:30:21 PM org.hibernate.cfg.Configuration doConfigure Das bedeutet: INFO: HHH000041: Configured SessionFactory: null OK! Das hier ist der Beginn, wo Hibernate seine Initialisierung dokumentiert. Komponenten – WS 2014/15 – Teil 13/Hibernate 43 Output (Auszug) II Hibernate: delete from customer Hibernate: insert into customer (FirstName, Hibernate: insert into customer (FirstName, Hibernate: insert into customer (FirstName, Hibernate: insert into customer (FirstName, Kunden: Name: Herbert Doener veggie: true Die Name: Hildegard Momms veggie: false mit Name: Daniel Maier veggie: true Name: Jana Moires veggie: true Das Löschen mit deleteAll() LastName, LastName, LastName, LastName, Ausgaben show() Vegetarian) Vegetarian) Vegetarian) Vegetarian) values values values values (?, (?, (?, (?, ?, ?, ?, ?, ?) ?) ?) ?) Die Inserts mit load() Das ist der Teil, wo mit load() die Gäste in die Tabelle Customer dokumentiert werden. Komponenten – WS 2014/15 – Teil 13/Hibernate 44 Die Datenbank nach einem Lauf Komponenten – WS 2014/15 – Teil 13/Hibernate 45 Nach dieser Anstrengung etwas Entspannung... Komponenten – WS 2014/15 – Teil 13/Hibernate 46