| Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 7. Auflage |
| << | < | > | >> | API | Kapitel 47 - 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 44.4.7 haben wir 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 Persistenz Beans orientiert sich stark an SQL und wird über ein spezielles Anfrageobjekt Query ausgeführt. Nachdem beispielsweise Listing 47.16 erfolgreich ausgeführt und die Datensätze für das Verzeichnis und die zwei anhängenden Datei-Objekte erstellt wurden, können wir mit Hilfe eines Query-Objekts die abgespeicherten Verzeichnissätze auslesen und beispielsweise auf der Kommandozeile ausgeben:
001 /* Listing4717.java */
002
003 import javax.persistence.*;
004 import java.util.List;
005
006 public class Listing4717
007 {
008 public static void main(String[] args)
009 {
010 //Erzeugen einer EntityManagerFactory mit Hilfe des symbolischen
011 //Namens aus dem Persistenz Descriptor (persistence.xml)
012 EntityManagerFactory emf =
013 Persistence.createEntityManagerFactory("persistenceExample");
014
015 //Erzeugen eines EntityManagers für den Zugriff auf
016 //die Datenbank
017 EntityManager manager = emf.createEntityManager();
018
019 //Beginn einer neuen Transanktion
020 EntityTransaction tx = manager.getTransaction();
021 tx.begin();
022
023 //Erzeugen einer Anfrage
024 Query query = manager.createQuery("select d from Verzeichnis d");
025
026 //Ausführen der Anfrage und ermittel der Ergebnisliste
027 List<Verzeichnis> directories = query.getResultList();
028
029 //Ausgabe der Datensätze
030 for(Verzeichnis directory : directories) {
031 System.out.println(directory.toString());
032 }
033
034 //Abschluss der Transaktion mit einem Commit
035 tx.commit();
036
037 //Freigabe der Ressourcen des EntityManagers
038 manager.close();
039
040 //Schließen der EntityManagerFactory und Freigeben der
041 //belegten Ressourcen
042 emf.close();
043 }
044 }
|
Listing4717.java |
Das Query-Objekt in Zeile 024 wird mit Hilfe einer SQL-ähnlichen Anfrage erzeugt und stellt das JPA-Pendant zu einem Statement dar, wie wir sie in Abschnitt 44.4.5 kennengelernt haben. Die allgemeine Syntax für SQL- und JPA-Anfragen finden Sie in Abschnitt 44.4.7. Im Unterschied zu den SQL-Anfragen operiert das Java Persistenz API allerdings ausschließlich auf Java-Objekten (wie beispielsweise Verzeichnis) - der Name der Datenbanktabelle spielt keine Rolle.
Durch Aufruf der Methode getResultList in Zeile 027 wird die Anfrage ausgeführt und das Ergebnis als Liste zurückgegeben. Hierbei muss der Typ der Liste natürlich zur formulierten Anfrage passen, andernfalls kommt es zu einer ClassCastException.
Bei einer umfangreichen Datenbank ist es natürlich indiskutabel, zunächst alle Datensätze einer Tabelle auszulesen und dann das gewünschte Objekt in eine Schleife zu ermitteln. Deshalb lässt sich auch im JPA die Suche über eine Where-Klausel einschränken. Ähnlich wie bei einem PreparedStatement in Abschnitt 44.4.6 verwenden wir dazu einen Platzhalter als Parameter für die Elemente des Suchausdrucks:
001 /* Listing4718.java */
002
003 import javax.persistence.*;
004
005 public class Listing4718
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 einer Anfrage mit dem Parameter :name
023 Query query = manager.createQuery(
024 "select d from Verzeichnis d where d.name = :name"
025 );
026
027 //Setzen des Parameters
028 query.setParameter("name", "temp");
029
030 //Auslesen eines einzelnen Ergenisses
031 Verzeichnis directory = (Verzeichnis) query.getSingleResult();
032 System.out.println(directory.toString());
033
034 //Abschluss der Transaktion mit einem Commit
035 tx.commit();
036
037 //Freigabe der Ressourcen des EntityManagers
038 manager.close();
039
040 //Schließen der EntityManagerFactory und Freigeben der
041 //belegten Ressourcen
042 emf.close();
043 }
044 }
|
Listing4718.java |
In Zeile 023 wird eine Query mit einer Einschränkung auf den Namen des Verzeichnisses definiert. Dabei ist zu beachten, dass 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 028 wird der zuvor definierte Parameter mit dem Wert "temp" gefüllt, der in der anschließenden Abfrage an seiner Stelle eingesetzt wird. Hier wird nur der Name des Parameters ohne führenden Doppelpunkt verwendet.
Um die Anfrage auszuführen, könnten wir nun analog zu Listing 47.17 die Methode getResultList aufrufen. Da wir nur einen Treffer erhalten, würde sie uns eine Liste der Länge 1 zurückgeben. Für diesen Fall definiert das Java Persistenz API mit der Methode getSingleResult eine Abkürzung, die den gesuchten Datensatz direkt zurückgibt.
In größeren Programmen werden Datenbankanfragen meist nicht nur an einer einzigen Stelle benötigt, sondern sie sollen in verschiedenen Programmteilen wiederverwendet werden. Für diese Anwendungsfälle sieht das JPA die Definition von Standardanfragen in Form einer sogenannten Named Query vor.
Eine NamedQuery ist im Grunde nichts anders als eine parametrisierte Anfrage, die an einer Persistenz Bean definiert und anschließend nur noch über ihren symbolischen Namen referenziert wird. Das folgende Listing zeigt die die Anfrage aus dem letzten Abschnitt als Named Query am Verzeichnis-Objekt:
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 @NamedQuery(name = "DIRECTORY_BY_NAME", 015 query = "select d from Verzeichnis d where d.name = :name") 016 public class Verzeichnis 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<Datei> files; 029 030 /** 031 * Geschützter Minimalkonstruktor zur Verwendung von Hibernate 032 */ 033 protected Verzeichnis() { 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 Verzeichnis(String name) 042 { 043 this.name = name; 044 this.files = new LinkedList<Datei>(); 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 List<Datei> getFiles() 068 { 069 return files; 070 } 071 072 public void setFiles(List<Datei> files) 073 { 074 this.files = files; 075 } 076 077 public boolean equals(Object o) 078 { 079 if (this == o) return true; 080 if (o == null || getClass() != o.getClass()) return false; 081 082 Verzeichnis dir = (Verzeichnis) o; 083 return !(id != null ? !id.equals(dir.id) : dir.id != null); 084 } 085 086 public int hashCode() 087 { 088 return id != null ? id.hashCode() : 0; 089 } 090 091 public String toString() 092 { 093 return "Directory[id:"+ id + ", name:" + name + "]"; 094 } 095 } |
Verzeichnis.java |
In Zeile 014 wird die Anfrage mit Hilfe der Annotation @NamedQuery zentral definiert und mit dem (frei wählbaren) symbolischen Namen DIRECTORY_BY_NAME versehen. Das folgende Listing zeigt, wie die Named Query aufgerufen werden kann:
001 /* Listing4720.java */
002
003 import javax.persistence.*;
004
005 public class Listing4720
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 //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 Verzeichnis directory = (Verzeichnis) 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 }
|
Listing4720.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 schließlich wird die Anfrage mit den Methoden getSingleResult oder getResultList ausgeführt.
![]() |
![]() |
Um mehrere benannte Anfragen an einer Entity zu definieren, fasst man die @NamedQuery-Annotationen einfach als Attribute einer einzelnen @NamedQueries-Annotation zusammen. |
|
![]() |
| 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 |