| Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 6. Auflage |
| << | < | > | >> | API | Kapitel 45 - Objektorientierte Persistenz |
Neben den Basisoperationen Anlegen, Speichern und Löschen eines Datensatzes ist die Suche nach Datensätzen eine weitere Hauptaufgabe der Datenbankzugriffsschicht. In Abschnitt 42.4.7 haben Sie hierfür die Datenbankanfragesprache SQL kennengelernt. Mit der sogenannten JPA Query Language steht eine solche Anfragesprache auch für die objektorientierte Zugriffsschicht zur Verfügung.
Die Anfragesprache für Persistence Beans orientiert sich stark an SQL und wird wie diese über ein spezielles Anfrageobjekt Query ausgeführt. Wenn Sie beispielsweise Listing 45.16 erfolgreich ausgeführt und die Datensätze für das Directory und die zwei anhängenden File-Objekte erstellt haben, können Sie nun mit Hilfe des Query-Objekts in Listing 45.17 die abgespeicherten Verzeichnisse auslesen und beispielsweise auf der Kommandozeile ausgeben.
001 /* Listing4517.java */
002
003 import javax.persistence.*;
004
005 public class Listing4517
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 einer Anfrage
023 Query query = manager.createQuery("select d from Directory d");
024
025 // Ausführen der Anfrage und ermittel der Ergebnisliste
026 List<Directory> directories = query.getResultList();
027
028 // Ausgabe der Datensätze
029 for(Directory directory : directories) {
030 System.out.println(directory.toString());
031 }
032
033 //Abschluss der Transaktion mit einem Commit
034 tx.commit();
035
036 //Freigabe der Ressourcen des EntityManagers
037 manager.close();
038
039 //Schließen der EntityManagerFactory und Freigeben der
040 //belegten Ressourcen
041 emf.close();
042 }
043 }
|
Listing4517.java |
Das Query-Objekt in Zeile 023 wird mit Hilfe einer SQL-ähnlichen Anfrage erzeugt und stellt das JPA-Pendant zu einem Statement dar, die Sie in Abschnitt 42.4.5 kennengelernt haben. Die allgemeine Syntax für SQL- und JPA-Anfragen finden Sie in Abschnitt 42.4.7. Im Unterschied zu den SQL-Anfragen operiert das Java Persistence API aber ausschließlich auf Java-Objekten wie Directory, während der Name der Datenbanktabelle keine Rolle spielt.
Durch Aufruf der Methode getResultList in Zeile 026 wird die Anfrage ausgeführt und das Ergebnis als Liste zurückgegeben. Hierbei muss der Typ der Liste natürlich zur formulierten Anfrage passen, da es sonst zu einer ClassCastException kommt.
Nun ist es bei einer umfangreichen Datenbank mühsam zunächst alle Datensätze einer Tabelle auszulesen und dann das gesuchte Objekt über eine Schleife zu ermitteln, weshalb sich die Suche über eine Where-Klausel zum Beispiel auf den Namen des Verzeichnisses einschränken lässt.
Ähnlich wie bei einem PreparedStatement in Abschnitt 42.4.6 verwenden wir hierfür einen Parameter als Platzhalter für den Namen des Verzeichnisses.
001 /* Listing4518.java */
002
003 import javax.persistence.*;
004
005 public class Listing4518
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 einer Anfrage mit dem Parameter :name
023 Query query =
024 manager.createQuery("select d from Directory d where d.name = :name");
025
026 // Setzen des Parameters
027 query.setParameter("name", "temp");
028
029 // Auslesen eines einzelnen Ergenisses
030 Directory directory = (Directory) query.getSingleResult();
031 System.out.println(directory.toString());
032
033 //Abschluss der Transaktion mit einem Commit
034 tx.commit();
035
036 //Freigabe der Ressourcen des EntityManagers
037 manager.close();
038
039 //Schließen der EntityManagerFactory und Freigeben der
040 //belegten Ressourcen
041 emf.close();
042 }
043 }
|
Listing4518.java |
In Zeile 024 wird eine Query mit einer Einschränkung auf den Namen des Verzeichnisses definiert. Dabei ist zu beachten, dass hierfür der Name des Java-Attributs (name) und nicht der Name der Spalte in der Datenbanktabelle (dname) verwendet wird. Der Name des Platzhalters ist frei wählbar und wird mit der Escape-Sequenz : eingeleitet.
In Zeile 027 wird der zuvor definierte Parameter schließlich mit Leben gefüllt. An dieser Stelle wird nur der Name des Parameters ohne führenden Doppelpunkt verwendet.
Um die Anfrage auszuführen, könnten wir nun analog zu Listing 45.17 die Methode getResultList aufrufen, die uns eine Liste der Länge 1 zurückgeben würde. Für Anfragen, die jedoch genau einen Datensatz als Ergebnis haben, definiert das Java Persistence API eine Abkürzung über die Methode getSingleResult in Zeile 030, die den gesuchten Datensatz direkt zurückgibt.
![]() |
![]() |
Wenn das Ergebnis der Anfrage aus mehr als einem oder keinem Datensatz besteht wirft die Methode getSingleResult eine Ausnahme. |
|
![]() |
In einer komplexen Anwendung werden verschiedene Datenbankanfragen nicht nur an einer Stelle benötigt, sondern in verschiedenen Programmteilen gleichermaßen verwendet. Für diese Anwendungsfälle sieht das Java Persistence API die Definition von Standardanfragen in Form einer sogenannten NamedQuery vor.
Eine NamedQuery ist im Grunde nichts anders als eine (parametrisierte) Anfrage, die typischerweise an einer Persistence Bean definiert und anschließend nur noch über ihren symbolischen Namen referenziert wird. Listing 45.19 zeigt die Anfrage aus Abschnitt 45.5.2 als benannte Anfrage am Directory-Objekt.
001 /* Listing4519.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 @NamedQuery(name = "DIRECTORY_BY_NAME", 015 query = "select d from Directory d where d.name = :name") 016 public class Directory { 017 018 @Id 019 @GeneratedValue 020 @Column(name = "did") 021 private Integer id; 022 023 @Column(name = "dname") 024 private String name; 025 026 @OneToMany(cascade = CascadeType.ALL, mappedBy = "directory") 027 @OrderBy(value = "name") 028 private List<File> files; 029 030 /** 031 * Geschützter Minimalkonstruktor zur Verwendung von Hibernate 032 */ 033 protected Directory() { 034 } 035 036 /** 037 * Öffentlicher Konstruktor zur Verwendung durch den Entwickler. 038 * Dieser Konstruktor definiert alle Pflichtfelder der JavaBean. 039 * @param name - Name des Verzeichniseintrags 040 */ 041 public Directory(String name) 042 { 043 this.name = name; 044 this.files = new LinkedList<File>(); 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 List<File> getFiles() 066 { 067 return files; 068 } 069 public void setFiles(List<File> files) 070 { 071 this.files = files; 072 } 073 074 public boolean equals(Object o) 075 { 076 if (this == o) return true; 077 if (o == null || getClass() != o.getClass()) return false; 078 079 Directory dir = (Directory) o; 080 return !(id != null ? !id.equals(dir.id) : dir.id != null); 081 } 082 083 public int hashCode() 084 { 085 return id != null ? id.hashCode() : 0; 086 } 087 088 public String toString() 089 { 090 return "Directory[id:"+ id + ", name:" + name + "]"; 091 } 092 } |
Listing4519.java |
In Zeile Listing 45.19 wird die Anfrage aus Listing 45.18 zentral abgelegt und mit dem frei wählbaren, symbolischen Namen DIRECTORY_BY_NAME verknüpft. Hierfür wird die Annotation @NamedQuery verwendet. Um diese Anfrage ausführen zu können wird nun lediglich der Name der Anfrage benötigt.
![]() |
![]() |
Um mehrere benannte Anfragen an einer Entity zu definieren, fassen Sie die @NamedQuery-Annotationen einfach als Attribute einer einzelnen @NamedQueries-Annotation zusammen. |
|
![]() |
001 /* Listing4520.java */
002
003 import javax.persistence.*;
004
005 public class Listing4520
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 // Referenzieren der benannten Anfrage mit dem Parameter :name
023 Query query = manager.createNamedQuery("DIRECTORY_BY_NAME");
024
025 // Setzen des Parameters
026 query.setParameter("name", "temp");
027
028 // Auslesen eines einzelnen Ergebnisses
029 Directory directory = (Directory) query.getSingleResult();
030 System.out.println(directory.toString());
031
032 //Abschluss der Transaktion mit einem Commit
033 tx.commit();
034
035 //Freigabe der Ressourcen des EntityManagers
036 manager.close();
037
038 //Schließen der EntityManagerFactory und Freigeben der
039 //belegten Ressourcen
040 emf.close();
041 }
042 }
|
Listing4520.java |
In Zeile 023 wird beim Aufruf der Methode createNamedQuery der Name der benannten Anfrage synonym zur Anfrage verwendet. Anschließend werden die definierten Parameter gesetzt und die Anfrage schließlich mit den Methoden getSingleResult oder getResultList ausgeführt.
| 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 |