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

47.4 Verknüpfen von Datensätzen



Die voranstehenden Abschnitte haben gezeigt, wie man einfache Tabellen der Datenbank mit Hilfe von Java Beans abbilden und Datensätze über den EntityManager anlegen, manipulieren und löschen kann. Dabei wurde die Tabelle eins zu eins als Java-Objekt abgebildet, ohne auf die objektorientierte Struktur der verknüpften Datensätze einzugehen.

Das E/R-Diagramm unserer kleinen Datenbank aus Abschnitt 44.3 zeigt allerdings nicht nur eine, sondern zwei Tabellen, die miteinander verknüpft sind:

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

Ein Verzeichnis besitzt zunächst nur eine ID did und einen Namen dname. Der in Listing 47.2 modellierte Schlüssel fatherdid verweist dagegen auf einen übergeordneten Datensatz, also ein Elternverzeichnis, und statt lediglich die Anzahl der Verzeichniseinträge entries abzubilden, wäre es schön, wenn wir gleich Zugriff auf die entsprechenden Objekte hätten. Wie dies mit der JPA realisiert werden kann, wollen wir uns im zweiten Teil dieses Kapitels ansehen.

47.4.1 Fortgeschrittenes Modellieren von Datenbanktabellen

Zunächst wollen wir uns dem Abbilden von Datenbanktabellen noch einmal von der objektorientierten Herangehensweise annähern. Dabei besteht ein Verzeichnis-Objekt zunächst einmal aus einem Namen und einer ID. Während der Name vom Anwender selbst vergeben werden muss und damit ein Pflichtattribut darstellt, handelt es sich bei der ID um einen technischen Schlüssel in der Datenbank, den der Anwender zwar auslesen, aber nicht einfach ändern kann. Das folgende Listing zeigt die Java Bean im Ausgangsstadium:

001 /* Verzeichnis.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 Verzeichnis 
011 {
012   private Integer id;                        
013   private String name;                       
014 
015   /**
016    * Geschützter Minimalkonstruktor zur Verwendung von Hibernate
017    */
018   protected Verzeichnis() {                    
019   }
020 
021   /**
022    * Öffentlicher Konstruktor zur Verwendung durch den Entwickler.
023    * Dieser Konstruktor definiert alle Pflichtfelder der JavaBean.
024    * @param name - Name des Verzeichniseintrags
025    */
026   public Verzeichnis(String name)
027   {
028     this.name = name;
029   }
030 
031   public Integer getId()
032   {
033     return id;
034   }
035 
036   protected void setId(Integer id)           
037   {
038     this.id = id;
039   }
040 
041   public String getName()
042   {
043     return name;
044   }
045 
046   public void setName(String name)
047   {
048     this.name = name;
049   }
050 
051   public boolean equals(Object o)
052   {
053     if (this == o) return true;
054     if (o == null || getClass() != o.getClass()) return false;
055 
056     Verzeichnis dir = (Verzeichnis) o;
057     return !(id != null ? !id.equals(dir.id) : dir.id != null);
058   }
059 
060   public int hashCode()
061   {
062     return id != null ? id.hashCode() : 0;
063   }
064 
065   public String toString()
066   {
067     return "Directory[id:"+ id + ", name:" + name +  "]";
068   }
069 }
Listing 47.9: Zweite Java Bean zum Abbilden der Tabelle dir

Die Klasse Verzeichnis bildet zunächst nur die beiden Attribute id in Zeile 012 und name in Zeile 013 ab. Die Namen der Attribute orientieren sich an den Java-Konventionen und wir achten darauf, dass der öffentliche Konstruktor das Pflichtfeld name übernimmt, so dass kein namenloses Verzeichnis erstellt werden kann.

Der parameterlose Konstruktor in Zeile 018 ist dem Persistenz-Framework geschuldet, das zwingend einen Standardkonstruktor benötigt. Um dessen Aufruf zu erschweren, schränken wir die Sichtbarkeit mit Hilfe des Modifiers protected ein. Da die ID des Datensatzes 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 47.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 den Wert null annehmen und damit einen nicht definierten Zustand abbilden kann. Das 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 Verzeichnis um die Methoden equals und hashCode aus Abschnitt 9.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 so 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 sie so mit der im Hintergrund arbeitenden Datenbank. Als Alternative zu Listing 47.2 werden wir die Annotationen diesmal direkt an den Attributen, statt an den zugehörigen Getter-Methoden anbringen:

001 /* Verzeichnis.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 Verzeichnis 
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 Verzeichnis() {
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 Verzeichnis(String name)
034   {
035     this.name = name;
036   }
037 
038   public Integer getId()
039   {
040     return id;
041   }
042 
043   protected void setId(Integer id)
044   {
045     this.id = id;
046   }
047 
048   public String getName()
049   {
050     return name;
051   }
052 
053   public void setName(String name)
054   {
055     this.name = name;
056   }
057 
058   public boolean equals(Object o)
059   {
060     if (this == o) return true;
061     if (o == null || getClass() != o.getClass()) return false;
062 
063     Verzeichnis dir = (Verzeichnis) o;
064     return !(id != null ? !id.equals(dir.id) : dir.id != null);
065   }
066 
067   public int hashCode()
068   {
069     return id != null ? id.hashCode() : 0;
070   }
071 
072   public String toString()
073   {
074     return "Directory[id:"+ id + ", name:" + name +  "]";
075   }
076 }
Listing 47.10: Mit Annotationen angereicherte Java Bean

Die Annotationen @Entity, @Table, @Id und Column wurden ja bereits mit Listing 47.2 eingeführt. Neu hinzugekommen ist @GeneratedValue in Zeile 015, um der Persistenzschicht anzuzeigen, dass der Wert des Attributs automatisch erzeugt und nicht vom Benutzer gesetzt werden soll.

Analog zur Klasse Verzeichnis können wir nun auch die Klasse Datei mit dem Pflichtattribut name definieren. Dabei bilden wir der Einfachheit halber das Änderungsdatum einer Datei über ein einzelnes Attribut mit Namen date ab:

001 /* Datei.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 Datei 
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 Datei() {
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 Datei(String name)
043   {
044     this.name = name;
045   }
046 
047   public Integer getId()
048   {
049     return id;
050   }
051  
052   protected void setId(Integer id)
053   {
054     this.id = id;
055   }
056 
057   public String getName()
058   {
059     return name;
060   }
061  
062   public void setName(String name)
063   {
064     this.name = name;
065   }
066 
067   public Integer getSize()
068   {
069     return size;
070   }
071  
072   public void setSize(Integer size)
073   {
074     this.size = size;
075   }
076 
077   public Date getDate()
078   {
079     return date;
080   }
081  
082   public void setDate(Date date)
083   {
084     this.date = date;
085   }
086 
087   public boolean equals(Object o)
088   {
089     if (this == o) return true;
090     if (o == null || getClass() != o.getClass()) return false;
091 
092     Datei file = (File) o;
093     return !(id != null ? !id.equals(file.id) : file.id != null);
094   }
095 
096   public int hashCode()
097   {
098     return id != null ? id.hashCode() : 0;
099   }
100 
101   public String toString() 
102   {
103     return "File[id:"+ id + ", name:" + name +  "]";
104   }
105 }
Listing 47.11: Java Bean zur Abbildung der Tabelle file

Um auch das Datei-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 47.3 wie folgt (Zeile 015):

001 <?xml version="1.0" encoding="ISO-8859-1"?>
002 
003 <!-- Persistenz 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>Verzeichnis</class> 
015     <class>Datei</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 47.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 47.6. Der einzige Unterschied ist, dass wir die ID des Datensatzes nicht mehr selbst vorgeben, sondern von der Persistenzschicht generieren lassen.

001 /* Listing4713.java */
002 
003 import javax.persistence.*;
004 
005 public class Listing4713
006 {
007   public static void main(String[] args)
008   {
009     //Erzeugen einer EntityManagerFactory mit Hilfe des symbolischen
010     //Namens aus dem Persistenz 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     Verzeichnis dir = new Verzeichnis("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 }
Listing4713.java
Listing 47.13: Anlegen eines Datensatzes

Das Verzeichnis-Objekt wird in Zeile 023 nur noch mit einem Namen initialisiert und erhält seine ID erst mit dem Speichern in Zeile 026. Die Ausgabeanweisung in Zeile 032 führt zu folgendem Ergebnis:

Directory[id:1, name:temp]

47.4.2 Modellieren von Relationen

Relationale Datenbanken verknüpfen Datensätze unterschiedlicher Tabellen mit Hilfe von Fremdschlüsseln. In diesem Abschnitt wollen wir uns ansehen, wie die referentielle Integrität, also die fachliche Konsistenz der verschiedenen Fremdschlüsselbeziehungen der Datenbank, objektorientiert modelliert werden kann.

Solche Referenzen können in unterschiedlichen Kardinalitäten vorliegen:

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 47.5: Kardinalitäten für Datenbankbeziehungen

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. Zwischen Datei und Verzeichnis besteht also eine N:1-Beziehung, da mehrere Dateien zu genau einem Verzeichniseintrag gehören können. Aus Sicht des Verzeichnis-Objekts würde es sich umgekehrt um eine 1:N-Beziehung handeln.

Diese Referenzen lassen sich auch mit der Persistenzschicht abbilden, indem ein Objekt auf das oder die anderen Objekte verweist. Wir erweitern dazu das Verzeichnis-Objekt um eine Liste von Datei-Objekten, um die zum Verzeichnis gehörenden Dateien aufzunehmen:

001 /* Verzeichnis.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 Verzeichnis 
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<Datei> files;
027 
028   /**
029    * Geschützter Minimalkonstruktor zur Verwendung von Hibernate
030    */
031   protected Verzeichnis() {                          
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 Verzeichnis(String name)
040   {
041     this.name = name;
042     this.files = new LinkedList<Datei>();         
043   }
044 
045   public Integer getId()
046   {
047     return id;
048   }
049 
050   protected void setId(Integer id)
051   {
052     this.id = id;
053   }
054 
055   public String getName()
056   {
057     return name;
058   }
059 
060   public void setName(String name)
061   {
062     this.name = name;
063   }
064 
065   public List<Datei> getFiles()
066   {
067     return files;
068   }
069 
070   public void setFiles(List<Datei> files)
071   {
072     this.files = files;
073   }
074 
075   public boolean equals(Object o)
076   {
077     if (this == o) return true;
078     if (o == null || getClass() != o.getClass()) return false;
079 
080     Verzeichnis dir = (Verzeichnis) o;
081     return !(id != null ? !id.equals(dir.id) : dir.id != null);
082   }
083 
084   public int hashCode()
085   {
086     return id != null ? id.hashCode() : 0;
087   }
088 
089   public String toString()
090   {
091     return "Directory[id:"+ id + ", name:" + name +  "]";
092   }
093 }
Listing 47.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 die Angabe von @OneToMany in Zeile 024. Mit dem Attribut cascade wird das Persistenz-Framework angewiesen, bestimmte Datenbankoperationen auch auf die referenzierten Datensätze anzuwenden. Über den Parameter CascadeType.ALL in Listing 47.14 weisen wir das Framework beispielsweise an, alle Datenbankoperationen auf Verzeichnisebene auch auf die anhängenden Dateien anzuwenden.

Da die Dateiobjekte zu einem Verzeichnis jedoch nicht als unsortiertes java.util.Set, sondern als nach Namen geordnete Liste ausgelesen werden sollen, fügen wir in Zeile 025 noch eine zweite Annotation @OrderBy hinzu. Sie 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 Datei.

Zu guter Letzt wollen wir verhindern, dass es bei einem Zugriff auf die Datei-Objekte eines Verzeichnis aufgrund einer nicht initialisierten Liste zu einer NullPointerException kommt. Deshalb erweitern wir den öffentlichen Konstruktor und initialisieren die Liste in Zeile 042. 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 47.6: Annotationen zur Modellierung von Datenbankreferenzen

Alle Annotationen aus Tabelle 47.6 können über eine Reihe von Attributen konfiguriert werden:

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 47.7: Attribute der Annotationen für Datenbankreferenzen

Wir können auch die inverse Relation von einer Datei auf das zugehörige Verzeichnis abbilden, also eine @ManyToOne-Beziehung:

001 /* Datei.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 Datei 
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 Verzeichnis directory;
033 
034   /**
035    * Geschützter Minimalkonstruktor zur Verwendung von Hibernate
036    */
037   protected Datei() {
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 Datei(String name)
046   {
047     this.name = name;
048   }
049 
050   public Integer getId()
051   {
052     return id;
053   }
054   
055   protected void setId(Integer id)
056   {
057     this.id = id;
058   }
059 
060   public String getName()
061   {
062     return name;
063   }
064   
065   public void setName(String name)
066   {
067     this.name = name;
068   }
069 
070   public Integer getSize()
071   {
072     return size;
073   }
074   
075   public void setSize(Integer size)
076   {
077     this.size = size;
078   }
079 
080   public Date getDate()
081   {
082     return date;
083   }
084   
085   public void setDate(Date date)
086   {
087     this.date = date;
088   }
089 
090   public Verzeichnis getDirectory() 
091   {
092     return directory;
093   }
094   
095   public void setDirectory(Verzeichnis directory) 
096   {
097     this.directory = directory;
098   }
099     
100   public boolean equals(Object o)
101   {
102     if (this == o) return true;
103     if (o == null || getClass() != o.getClass()) return false;
104 
105     Datei file = (Datei) o;
106     return !(id != null ? !id.equals(file.id) : file.id != null);
107   }
108 
109   public int hashCode()
110   {
111     return id != null ? id.hashCode() : 0;
112   }
113 
114   public String toString()
115   {
116     return "File[id:"+ id + ", name:" + name +  "]";
117   }
118 }
Datei.java
Listing 47.15: Modellieren von N:1-Referenzen

Nun sind die beiden Persistenz Beans Verzeichnis und Datei 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 dabei ganz auf die objektorientierte Sichtweise konzentrieren und die Realisierung mittels Fremdschlüsseln vollständig vergessen.

Das folgende Listing 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 47.14 zu nutze, das den Aufruf von persist auch auf die referenzierten Datei-Objekte anwendet.

001 /* Listing4716.java */
002 
003 import javax.persistence.*;
004 
005 public class Listing4716
006 {
007   public static void main(String[] args)
008   {
009     //Erzeugen einer EntityManagerFactory mit Hilfe des symbolischen
010     //Namens aus dem Persistenz 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     Verzeichnis dir = new Verzeichnis("temp");
024 
025     Datei fileTest = new Datei("test.txt");
026     dir.getFiles().add(fileTest);
027     fileTest.setDirectory(dir);
028 
029     Datei fileInfo = new Datei("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 }
Listing4716.java
Listing 47.16: Anlegen mehrerer verknüpfter Datensätze


 Titel   Inhalt   Suchen   Index   DOC  Handbuch der Java-Programmierung, 7. Auflage, Addison Wesley, Version 7.0
 <<    <     >    >>   API  © 1998, 2011 Guido Krüger & Heiko Hansen, http://www.javabuch.de