Titel   Inhalt   Suchen   Index   DOC  Handbuch der Java-Programmierung, 6. Auflage
 <<    <     >    >>   API  Kapitel 45 - Objektorientierte Persistenz

45.4 Verknüpfen von Datensätzen



Die voranstehenden Abschnitte haben Ihnen gezeigt, wie Sie einfache Tabellen der Datenbank mit Hilfe von Java Beans abbilden und Datensätze über den EntityManager anlegen, manipulieren und löschen können. Hierbei wurde die Tabelle eins zu eins als Java-Objekt abgebildet, ohne auf die objektorientierte Struktur der verknüpften Datensätze einzugehen. Werfen wir noch einmal einen Blick auf das E/R-Diagramm der Datenbank aus Abschnitt 42.3.

Abbildung 45.2: E/R-Diagramm für DirDB

Wie in Abbildung 45.2 zu sehen ist, besitzt ein Verzeichnis zunächst nur eine Id did und einen Namen dname. Der in Listing 45.2 modellierte Schlüssel fatherdid verweist hingegen auf einen übergeordneten Datensatz, also ein Elternverzeichnis und statt lediglich die Anzahl der Verzeichniseinträge entries abzubilden, wäre es schön wenn wir stattdessen gleich Zugriff auf die entsprechenden Objekte hätten. Dies wollen wir im zweiten Teil dieses Kapitels mit Hilfe der JPA realisieren.

45.4.1 Fortgeschrittenes Modellieren von Datenbanktabellen

Als Erstes wollen wir uns dem Abbilden von Datenbanktabellen noch einmal von der objektorientierten Herangehensweise annähern. Dabei besteht ein Directory-Objekt zunächst einmal aus einem Namen und einer Id. Während Ersterer vom Anwender selbst vergeben werden muss und damit ein Pflichtattribut darstellt, handelt es sich bei der Id um einen technischen Schlüssel der Datenbank, den der Anwender zwar auslesen, jedoch nicht wahllos ändern kann. Listing 45.9 zeigt die Java Bean im Ausgangsstadium.

001 /* Listing4509.java */
002 
003 import javax.persistence.*;
004 
005 /**
006  * Diese Klasse repräsentiert die Tabelle 'dir' der 'DirDB'
007  * Jede Instanz der Klasse repräsentiert wiederum einen
008  * Datensatz
009  */
010 public class Directory {
011 
012     private Integer id;                        
013 
014     private String name;                       
015 
016     /**
017      * Geschützter Minimalkonstruktor zur Verwendung von Hibernate
018      */
019     protected Directory() {                    
020     }
021 
022     /**
023      * Öffentlicher Konstruktor zur Verwendung durch den Entwickler.
024      * Dieser Konstruktor definiert alle Pflichtfelder der JavaBean.
025      * @param name - Name des Verzeichniseintrags
026      */
027     public Directory(String name)
028     {
029         this.name = name;
030     }
031 
032     public Integer getId()
033     {
034         return id;
035     }
036     protected void setId(Integer id)           
037     {
038         this.id = id;
039     }
040 
041     public String getName()
042     {
043         return name;
044     }
045     public void setName(String name)
046     {
047         this.name = name;
048     }
049 
050     public boolean equals(Object o)
051     {
052         if (this == o) return true;
053         if (o == null || getClass() != o.getClass()) return false;
054 
055         Directory dir = (Directory) o;
056         return !(id != null ? !id.equals(dir.id) : dir.id != null);
057     }
058 
059     public int hashCode()
060     {
061         return id != null ? id.hashCode() : 0;
062     }
063 
064     public String toString()
065     {
066         return "Directory[id:"+ id + ", name:" + name +  "]";
067     }
068 }
Listing4509.java
Listing 45.9: Zweite Java Bean zum Abbilden der Tabelle dir

Die Klasse Directory in Listing 45.9 bildet zunächst nur die beiden Attribute id in Zeile 012 und name in Zeile 014 ab. Die Namen der Attribute orientieren sich hierbei an den Java-Konventionen und berücksichtigen in keiner Weise die möglichen Vorgaben der Datenbank. Des Weiteren wird darauf geachtet, dass der öffentliche Konstruktor das Pflichtfeld name übernimmt, so dass kein namenloses Verzeichnis erstellt werden kann.

Der parameterlose Konstruktor in Zeile 019 ist dem Persistenz-Framework geschuldet, das zwingend einen Standardkonstruktor benötigt. Um dessen Verwendung in der Anwendung jedoch einzuschränken wird die Sichtbarkeit über den Modifier protected eingeschränkt.

Da die Id des Datensatzes in diesem Beispiel ausnahmslos von der Persistenzschicht verwaltet werden soll, ist in Zeile 036 auch der Zugriff auf dieses Attribut eingeschränkt.

Eine weitere Neuerung gegenüber Listing 45.2 findet sich schließlich in der Verwendung des Objekttyps Integer statt des Basistyps int für die Id des Datensatzes. Der Objekttyp hat gegenüber den Basistypen den Vorteil, dass er auf null belassen werden und damit einen nicht definierten Zustand abbilden kann. Dies ist beispielsweise dann der Fall, wenn die Instanz zwar über einen Konstruktor erzeugt, aber noch nicht in der Datenbank gespeichert wurde.

Abschließend wird die Klasse Directory um die Methoden equals und hashCode aus Abschnitt 8.1.2 erweitert, um die Identität eines Datensatzes überprüfen zu können. Diese Methoden stellen sicher, dass Hibernate einen in der Datenbank eindeutig referenzierten Datensatz über dessen Id auch javaseitig identifizieren und beispielsweise das doppelte Laden einer logisch identischen Instanz vermeiden kann.

Als Nächstes versehen wir die Java Bean mit den für die Persistenzschicht notwendigen Metainformationen und verknüpfen diese so mit der im Hintergrund arbeitenden Datenbank. Als Alternative zu Listing 45.2 werden wir die Annotationen diesmal direkt an den Attributen, statt an den zugehörigen Gettern anbringen.

001 /* Listing4510.java */
002 
003 import javax.persistence.*;
004 
005 /**
006  * Diese Klasse repräsentiert die Tabelle 'dir' der 'DirDB'
007  * Jede Instanz der Klasse repräsentiert wiederum einen
008  * Datensatz
009  */
010 @Entity
011 @Table( name = "dir" )
012 public class Directory {
013 
014     @Id
015     @GeneratedValue                            
016     @Column(name = "did")
017     private Integer id;
018 
019     @Column(name = "dname")
020     private String name;
021 
022     /**
023      * Geschützter Minimalkonstruktor zur Verwendung von Hibernate
024      */
025     protected Directory() {
026     }
027 
028     /**
029      * Öffentlicher Konstruktor zur Verwendung durch den Entwickler.
030      * Dieser Konstruktor definiert alle Pflichtfelder der JavaBean.
031      * @param name - Name des Verzeichniseintrags
032      */
033     public Directory(String name)
034     {
035         this.name = name;
036     }
037 
038     public Integer getId()
039     {
040         return id;
041     }
042     protected void setId(Integer id)
043     {
044         this.id = id;
045     }
046 
047     public String getName()
048     {
049         return name;
050     }
051     public void setName(String name)
052     {
053         this.name = name;
054     }
055 
056     public boolean equals(Object o)
057     {
058         if (this == o) return true;
059         if (o == null || getClass() != o.getClass()) return false;
060 
061         Directory dir = (Directory) o;
062         return !(id != null ? !id.equals(dir.id) : dir.id != null);
063     }
064 
065     public int hashCode()
066     {
067         return id != null ? id.hashCode() : 0;
068     }
069 
070     public String toString()
071     {
072         return "Directory[id:"+ id + ", name:" + name +  "]";
073     }
074 }
Listing4510.java
Listing 45.10: Mit Annotationen angereicherte Java Bean

Die Annotationen @Entity, @Table, @Id und Column sind ja bereits mit Listing 45.2 eingeführt worden. Neu hinzugekommen ist nun die Annotation @GeneratedValue in Zeile 015. Diese zeigt der Persistenzschicht an, dass der Wert des Attributs automatisch erzeugt und nicht vom Benutzer gesetzt werden soll.

Nun können wir ganz analog zur Klasse Directory die Klasse File mit dem Pflichtattribut name definieren. Dabei bilden wir der Einfachheit halber das Änderungsdatum einer Datei über ein einzelnes Attribut mit Namen date ab.

001 /* Listing4511.java */
002 
003 import javax.persistence.*;
004 import java.util.Date;
005 
006 /**
007  * Diese Klasse repräsentiert die Tabelle 'file' der 'DirDB'
008  * Jede Instanz der Klasse repräsentiert wiederum einen
009  * Datensatz
010  */
011 
012 @Entity
013 @Table( name = "file" )
014 public class File {
015 
016     @Id
017     @GeneratedValue
018     @Column(name = "fid")
019     private Integer id;
020 
021     @Column(name = "fname")                                 
022     private String name;
023 
024     @Column(name = "dsize")
025     private Integer size;
026 
027     @Column(name = "fdate")
028     private Date date;
029 
030     /**
031      * Geschützter Minimalkonstruktor zur Verwendung durch 
032      * die Persistenzschicht
033      */
034     protected File() {
035     }
036 
037     /**
038      * Öffentlicher Konstruktor zur Verwendung durch den Entwickler.
039      * Dieser Konstruktor definiert alle Pflichtfelder der JavaBean.
040      * @param name - Name der Datei
041      */
042     public File(String name)
043     {
044         this.name = name;
045     }
046 
047     public Integer getId()
048     {
049         return id;
050     }
051     protected void setId(Integer id)
052     {
053         this.id = id;
054     }
055 
056     public String getName()
057     {
058         return name;
059     }
060     public void setName(String name)
061     {
062         this.name = name;
063     }
064 
065     public Integer getSize()
066     {
067         return size;
068     }
069     public void setSize(Integer size)
070     {
071         this.size = size;
072     }
073 
074     public Date getDate()
075     {
076         return date;
077     }
078     public void setDate(Date date)
079     {
080         this.date = date;
081     }
082 
083     public boolean equals(Object o)
084     {
085         if (this == o) return true;
086         if (o == null || getClass() != o.getClass()) return false;
087 
088         File file = (File) o;
089         return !(id != null ? !id.equals(file.id) : file.id != null);
090     }
091 
092     public int hashCode()
093     {
094         return id != null ? id.hashCode() : 0;
095     }
096 
097     public String toString() 
098     {
099         return "File[id:"+ id + ", name:" + name +  "]";
100     }
101 }
Listing4511.java
Listing 45.11: Java Bean zur Abbildung der Tabelle file

Um auch das File-Objekt über den EntityManager der Persistenzschicht verwalten zu können, müssen wir die Klasse noch im Persistence Deskriptor (persistence.xml) angeben. Hierfür erweitern wir Listing 45.3 wie in Zeile 015 gezeigt.

001 <?xml version="1.0" encoding="ISO-8859-1"?>
002 
003 <!-- Persistence Descriptor zur Konfiguration -->
004 <persistence>
005 
006   <!-- Hinterlegen eines symbolischen Namens -->
007   <persistence-unit name="persistenceExample" 
008                     transaction-type="RESOURCE_LOCAL"> 
009 
010     <!-- Zu verwendende Implementierung -->
011     <provider>org.hibernate.ejb.HibernatePersistence</provider>
012 
013     <!-- Persistierbare Klassen -->
014     <class>Directory</class> 
015     <class>File</class> 
016 
017     <!-- Konfiguration der Hibernate Implementierung -->
018     <properties>
019       <!-- Name des intern verwendeten JDBC-Treibers -->
020       <property name="hibernate.connection.driver_class"
021                 value="org.hsqldb.jdbcDriver"/> 
022 
023       <!-- URL der zu verwendenden Datenbank -->
024       <property name="hibernate.connection.url"
025                 value="jdbc:hsqldb:hsqldbtest"/> 
026 
027       <!-- SQL-Dialect, den Hibernate verwenden soll -->
028       <property name="hibernate.dialect"
029                 value="org.hibernate.dialect.HSQLDialect"/>
030 
031       <!-- Benutzername und Passwort; Standardwerte der HSQLDB -->
032       <property name="hibernate.connection.username" value="SA"/> 
033       <property name="hibernate.connection.password" value=""/> 
034 
035       <!-- Flag, ob Tabellen automatisch erzeugt werden sollen -->
036       <property name="hibernate.hbm2ddl.auto" value="create"/> 
037 
038       <!-- Flag, ob SQL-Statements ausgegeben werden sollen -->
039       <property name="hibernate.show_sql" value="true"/> 
040 
041       <!-- Flag, ob SQL-Statements formatiert werden sollen -->
042       <property name="hibernate.format_sql" value="true"/> 
043     </properties>
044   </persistence-unit>
045 </persistence>
persistence.xml.ext
Listing 45.12: Konfigurationsdatei für das Java Persistenz API

Das Speichern, Manipulieren und Löschen der Persistenz Beans erfolgt ganz analog zum ersten Beispiel in Listing 45.6. Der einzige Unterschied ist, dass wir die Id des Datensatzes nicht mehr selbst bestimmen, sondern von der Persistenzschicht verwalten lassen.

001 /* Listing4513.java */
002 
003 import javax.persistence.*;
004 
005 public class Listing4513
006 {
007     public static void main(String[] args)
008     {
009         //Erzeugen einer EntityManagerFactory mit Hilfe des symbolischen
010         //Namens aus dem Persistence Descriptor (persistence.xml)
011         EntityManagerFactory emf =
012                 Persistence.createEntityManagerFactory("persistenceExample");
013 
014         //Erzeugen eines EntityManagers für den Zugriff auf
015         //die Datenbank
016         EntityManager manager = emf.createEntityManager();
017 
018         //Beginn einer neuen Transanktion
019         EntityTransaction tx = manager.getTransaction();
020         tx.begin();
021 
022         //Erzeugen eines neuen Java-Objekts
023         Directory dir = new Directory("temp");    
024 
025         //Speichern des Java-Objekts mit Hilfe des EntityManagers
026         manager.persist(dir);                     
027 
028         //Abschluss der Transaktion mit einem Commit
029         tx.commit();
030 
031         // Ausgabe der Id des Datensatzes
032         System.out.println(dir.toString());       
033 
034         //Freigabe der Ressourcen des EntityManagers
035         manager.close();
036 
037         //Schließen der EntityManagerFactory und Freigeben der
038         //belegten Ressourcen
039         emf.close();
040     }
041 }
Listing4513.java
Listing 45.13: Anlegen eines Datensatzes

Das Directory-Objekt wird in Zeile 023 nur noch mit einem Namen initialisiert und erhält seine Id erst mit dem Speichern in Zeile 026. Die Ausgabe in Zeile 032 führt anschließend zu folgendem Ergebnis:

Directory[id:1, name:temp]

45.4.2 Modellieren von Relationen

Nachdem Abschnitt 45.4.1 auf die automatische Verwaltung der Datenbankschlüssel durch die Persistenzschicht eingegangen ist zeigt dieser Abschnitt, wie die referentielle Integrität von Datenbanken objektorientiert modelliert werden kann.

Relationale Datenbanken verknüpfen Datensätze über Fremdschlüssel aus anderen Tabellen, um so die Zugehörigkeit eines Datensatzes anzuzeigen. In unserem Beispiel speichert jeder file-Datensatz die Id des zugehörigen dir-Datensatzes um eindeutig anzuzeigen, zu welchem Verzeichnis die jeweilige Datei gehört.

Solche Referenzen können in unterschiedlichen Kardinalitäten vorliegen, die in Tabelle 45.5 beschrieben werden. Beim Beispiel der Datei handelt es sich natürlich um eine N:1-Beziehung, da mehrere Dateien zu genau einem Verzeichniseintrag gehören können. Aus Sicht des Directory-Objekts würde es sich dann um eine 1:N-Beziehung handeln.

Kurzform Name Bedeutung
1:1 Eins-zu-Eins Jeder Datensatz einer Tabelle ist höchstens einem Datensatz in der anderen Tabelle zugeordnet
1:N Eins-zu-N Dem Datensatz dieser Tabelle können mehrere Datensätze einer anderen Tabelle zugordnet sein
N:1 N-zu-Eins Mehrere Datensätze dieser Tabelle können auf ein und denselben Datensatz einer anderen Tabelle verweisen
M:N M-zu-N Der Datensatz kann von verschiedenen Datensätzen referenziert werden und gleichzeitig auf mehrere Datensätze verweisen

Tabelle 45.5: Kardinalitäten für Datenbankbeziehungen

Diese Referenzen lassen sich auch mit der Persistenzschicht abbilden, wobei in diesem Fall eine Persistenz Bean auf eine oder mehrere andere verweist. In Listing 45.14 wird das Directory-Objekt nun um eine Liste von File-Objekten erweitert, um die zum Verzeichnis gehörenden Dateien aufzunehmen.

001 /* Listing4514.java */
002 
003 import javax.persistence.*;
004 import java.util.List;
005 import java.util.LinkedList;
006 
007 /**
008  * Diese Klasse repräsentiert die Tabelle 'dir' der 'DirDB'
009  * Jede Instanz der Klasse repräsentiert wiederum einen
010  * Datensatz
011  */
012 @Entity
013 @Table( name = "dir" )
014 public class Directory {
015 
016     @Id
017     @GeneratedValue
018     @Column(name = "did")
019     private Integer id;
020 
021     @Column(name = "dname")
022     private String name;
023 
024     @OneToMany(cascade = CascadeType.ALL)            
025     @OrderBy(value = "name")                         
026     private List<File> files;
027 
028     /**
029      * Geschützter Minimalkonstruktor zur Verwendung von Hibernate
030      */
031     protected Directory() {                          
032     }
033 
034     /**
035      * Öffentlicher Konstruktor zur Verwendung durch den Entwickler.
036      * Dieser Konstruktor definiert alle Pflichtfelder der JavaBean.
037      * @param name - Name des Verzeichniseintrags
038      */
039     public Directory(String name)
040     {
041         this.name = name;
042         this.files = new LinkedList<File>();         
043     }
044 
045     public Integer getId()
046     {
047         return id;
048     }
049     protected void setId(Integer id)
050     {
051         this.id = id;
052     }
053 
054     public String getName()
055     {
056         return name;
057     }
058     public void setName(String name)
059     {
060         this.name = name;
061     }
062 
063     public List<File> getFiles()
064     {
065         return files;
066     }
067     public void setFiles(List<File> files)
068     {
069         this.files = files;
070     }
071 
072     public boolean equals(Object o)
073     {
074         if (this == o) return true;
075         if (o == null || getClass() != o.getClass()) return false;
076 
077         Directory dir = (Directory) o;
078         return !(id != null ? !id.equals(dir.id) : dir.id != null);
079     }
080 
081     public int hashCode()
082     {
083         return id != null ? id.hashCode() : 0;
084     }
085 
086     public String toString()
087     {
088         return "Directory[id:"+ id + ", name:" + name +  "]";
089     }
090 }
Listing4514.java
Listing 45.14: Modellieren von 1:N-Referenzen

Genau wie die Basisattribute einer Tabelle werden auch die referenzierten Datensätze über Annotationen mit den notwendigen Metainformationen verknüpft. Für eine 1:N-Relation genügt dabei prinzipiell die Angabe von @OneToMany in Zeile 024, wenn der referenzierte Typ File ebenfalls eine Persistenz Bean ist. Das Attribut cascade gestattet es das Persistenz-Framework anzuweisen, bestimmte Datenbankoperationen, wie beispielsweise das Löschen eines Directory auch auf die referenzierten Datensätze anzuwenden. Über den Parameter CascadeType.ALL in Listing 45.14 weisen wir das Framework an, alle Datenbankoperationen auf Verzeichnisebene auch auf die anhängenden Dateien anzuwenden.

Da die Dateiobjekte zu einem Verzeichnis jedoch nicht als ungeordnetes java.util.Set, sondern als nach Namen geordnete Liste ausgelesen werden sollen, fügen wir in Zeile 025 noch eine zweite Annotation @OrderBy hinzu. Diese bewirkt, dass die Datensätze nach dem Namen der referenzierten Java Bean sortiert werden. Die Bezeichnung der Datenbankspalte unter der der Name einer Datei abgespeichert wird, spielt hier keine Rolle, es zählt einzig der Name des Attributs in der Java Bean File.

Abschließend sollten wir noch verhindern, dass es bei einem Zugriff auf die File-Objekte eines Directory aufgrund einer nicht initialisierten Liste zu einer unschönen NullPointerException kommt, weshalb wir den öffentlichen Konstruktor erweitern und die Liste in Zeile 042 initialisieren. Bemerkenswert an dieser Stelle ist, dass wir den vom Persistenz-Framework verwendeten Minimalkonstruktor in Zeile 031 nicht entsprechend erweitern müssen: Auch wenn zu einem Verzeichnis keine Dateien existieren, wird das Persistenz-Framework refenzierende Collections stets leer initialisieren.

Annotation Beschreibung
@OneToMany Modelliert eine 1:N-Relation
@ManyToOne Modelliert eine N:1-Relation
@OneToOne Modelliert eine 1:1-Relation
@ManyToMany Modelliert eine M:N-Relation

Tabelle 45.6: Annotationen zur Modellierung von Datenbankreferenzen

Alle Annotationen aus Tabelle 45.6 können über eine Reihe von Attributen konfiguriert werden, die in Tabelle 45.7 aufgeführt sind:

Attribut Beschreibung
cascade Welche Datenbankoperationen sollen auch auf das referenzierte Objekt angewendet werden
fetch Wann sollen die referenzierten Datensätze geladen werden FetchType.EAGER lädt die Datensätze sofort, FetchType.LAZY lädt die Datensätze nur bei Bedarf nach.
mappedBy Name des Attributs im referenzierten Datensatz, das die inverse Relation abbildet. Wird nur benötigt, wenn mehrere Rückreferenzen in Frage kommen.
targetEntity Typ des referenzierten Datensatzes. Wird nur benötigt, wenn dies nicht aus der typisierten Liste hervorgeht.

Tabelle 45.7: Attribute der Annotationen für Datenbankreferenzen

Wir können auch die inverse Relation von einer Datei auf das zugehörige Verzeichnis abbilden. In diesem Fall handelt es sich um eine @ManyToOne-Beziehung, wie in Listing 45.15 gezeigt:

001 /* Listing4515.java */
002 
003 import javax.persistence.*;
004 import java.util.Date;
005 
006 /**
007  * Diese Klasse repräsentiert die Tabelle 'file' der 'DirDB'
008  * Jede Instanz der Klasse repräsentiert wiederum einen
009  * Datensatz
010  */
011 
012 @Entity
013 @Table( name = "file" )
014 public class File {
015 
016     @Id
017     @GeneratedValue
018     @Column(name = "fid")
019     private Integer id;
020 
021     @Column(name = "fname")                                 
022     private String name;
023 
024     @Column(name = "dsize")
025     private Integer size;
026 
027     @Column(name = "fdate")
028     private Date date;
029 
030     @ManyToOne
031     @JoinColumn(name = "did")
032     private Directory directory;
033 
034     /**
035      * Geschützter Minimalkonstruktor zur Verwendung von Hibernate
036      */
037     protected File() {
038     }
039 
040     /**
041      * Öffentlicher Konstruktor zur Verwendung durch den Entwickler.
042      * Dieser Konstruktor definiert alle Pflichtfelder der JavaBean.
043      * @param name - Name der Datei
044      */
045     public File(String name)
046     {
047         this.name = name;
048     }
049 
050     public Integer getId()
051     {
052         return id;
053     }
054     protected void setId(Integer id)
055     {
056         this.id = id;
057     }
058 
059     public String getName()
060     {
061         return name;
062     }
063     public void setName(String name)
064     {
065         this.name = name;
066     }
067 
068     public Integer getSize()
069     {
070         return size;
071     }
072     public void setSize(Integer size)
073     {
074         this.size = size;
075     }
076 
077     public Date getDate()
078     {
079         return date;
080     }
081     public void setDate(Date date)
082     {
083         this.date = date;
084     }
085 
086     public Directory getDirectory() 
087     {
088         return directory;
089     }
090     public void setDirectory(Directory directory) 
091     {
092         this.directory = directory;
093     }
094     
095     public boolean equals(Object o)
096     {
097         if (this == o) return true;
098         if (o == null || getClass() != o.getClass()) return false;
099 
100         File file = (File) o;
101         return !(id != null ? !id.equals(file.id) : file.id != null);
102     }
103 
104     public int hashCode()
105     {
106         return id != null ? id.hashCode() : 0;
107     }
108 
109     public String toString()
110     {
111         return "File[id:"+ id + ", name:" + name +  "]";
112     }
113 }
Listing4515.java
Listing 45.15: Modellieren von 1:N-Referenzen

Nun sind die beiden Persistenz Beans Directory und File miteinander verknüpft und referenzieren sich in beide Richtungen. Aus Sicht der Java-Objekte können wir jetzt auf einfache Weise die Dateien eines Verzeichnisses ausgeben oder das Elternverzeichnis einer Datei ermitteln. Dank der Annotationen des Persistenz-Frameworks können wir uns ganz auf die objektorientierte Sichtweise konzentrieren und die Abbildung über Fremdschlüssel auf Seiten der Datenbank vollständig vergessen.

Listing 45.16 zeigt, wie die miteinander verknüpften Datensätze mit Hilfe des EntityManager gespeichert werden können. Hierbei machen wir uns das Attribut cascade aus Listing 45.14 zu nutze, das den Aufruf von persist auch auf die referenzierten File-Objekte anwendet.

001 /* Listing4516.java */
002 
003 import javax.persistence.*;
004 
005 public class Listing4516
006 {
007     public static void main(String[] args)
008     {
009         //Erzeugen einer EntityManagerFactory mit Hilfe des symbolischen
010         //Namens aus dem Persistence Descriptor (persistence.xml)
011         EntityManagerFactory emf =
012                 Persistence.createEntityManagerFactory("persistenceExample");
013 
014         //Erzeugen eines EntityManagers für den Zugriff auf
015         //die Datenbank
016         EntityManager manager = emf.createEntityManager();
017 
018         //Beginn einer neuen Transanktion
019         EntityTransaction tx = manager.getTransaction();
020         tx.begin();
021 
022         //Erzeugen und Verknüpfen der Java-Objekte
023         Directory dir = new Directory("temp");
024 
025         File fileTest = new File("test.txt");
026         dir.getFiles().add(fileTest);
027         fileTest.setDirectory(dir);
028 
029         File fileInfo = new File("info.txt");
030         dir.getFiles().add(fileInfo);
031         fileInfo.setDirectory(dir);
032 
033         //Speichern des Verzeichnisses und der anhängenden Objekte
034         manager.persist(dir);
035 
036         //Abschluss der Transaktion mit einem Commit
037         tx.commit();
038 
039         //Freigabe der Ressourcen des EntityManagers
040         manager.close();
041 
042         //Schließen der EntityManagerFactory und Freigeben der
043         //belegten Ressourcen
044         emf.close();
045     }
046 }
Listing4516.java
Listing 45.16: Anlegen mehrerer verknüpfter Datensätze


 Titel   Inhalt   Suchen   Index   DOC  Handbuch der Java-Programmierung, 6. Auflage, Addison Wesley, Version 6.0
 <<    <     >    >>   API  © 1998, 2009 Guido Krüger & Thomas Stark, http://www.javabuch.de