Ich verwende JPA in meinem Projekt.
Ich kam zu einer Abfrage, bei der ich eine Verknüpfungsoperation für fünf Tabellen ausführen muss. Also habe ich eine native Abfrage erstellt, die fünf Felder zurückgibt.
Jetzt möchte ich das Ergebnisobjekt in eine Java-POJO-Klasse konvertieren, die dieselben fünf Strings enthält.
Gibt es in JPA eine Möglichkeit, dieses Ergebnis direkt in die POJO-Objektliste umzuwandeln?
Ich kam zu folgender Lösung ..
@NamedNativeQueries({
@NamedNativeQuery(
name = "nativeSQL",
query = "SELECT * FROM Actors",
resultClass = db.Actor.class),
@NamedNativeQuery(
name = "nativeSQL2",
query = "SELECT COUNT(*) FROM Actors",
resultClass = XXXXX) // <--------------- problem
})
Müssen wir hier in resultClass eine Klasse bereitstellen, die eine tatsächliche JPA-Entität ist? ODER Wir können es in jede JAVA POJO-Klasse konvertieren, die dieselben Spaltennamen enthält.
Antworten:
JPA bietet eine
SqlResultSetMapping
, mit der Sie alle Ergebnisse Ihrer nativen Abfrage einer Entität zuordnen könnenoder eine benutzerdefinierte Klasse.EDIT JPA 1.0 erlaubt keine Zuordnung zu Nicht-Entitätsklassen. Nur in JPA 2.1 wurde ein ConstructorResult hinzugefügt, um Rückgabewerte einer Java-Klasse zuzuordnen.
Für das Problem von OP mit dem Abrufen der Zählung sollte es außerdem ausreichen, eine Ergebnismengenzuordnung mit einer einzelnen zu definieren
ColumnResult
quelle
ConstructorResult
einen der Parameter hinzugefügtSqlResultSetMapping
, mit denen ein Pojo mit allen im Konstruktor festgelegten Feldern verwendet werden kann. Ich werde die Antwort aktualisieren.Ich habe ein paar Lösungen dafür gefunden.
Verwenden zugeordneter Entitäten (JPA 2.0)
Mit JPA 2.0 ist es nicht möglich, eine native Abfrage einem POJO zuzuordnen, sondern nur mit einer Entität.
Zum Beispiel:
In diesem Fall
Jedi
muss es sich jedoch um eine zugeordnete Entitätsklasse handeln.Eine Alternative, um die ungeprüfte Warnung hier zu vermeiden, wäre die Verwendung einer benannten nativen Abfrage. Wenn wir also die native Abfrage in einer Entität deklarieren
Dann können wir einfach tun:
Dies ist sicherer, wir können jedoch weiterhin eine zugeordnete Entität verwenden.
Manuelle Zuordnung
Eine Lösung, die ich ein wenig experimentiert habe (vor der Ankunft von JPA 2.1), war das Mapping gegen einen POJO-Konstruktor mit ein wenig Reflexion.
Diese Methode verwendet im Grunde genommen ein Tupel-Array (wie es von nativen Abfragen zurückgegeben wird) und ordnet es einer bereitgestellten POJO-Klasse zu, indem nach einem Konstruktor gesucht wird, der dieselbe Anzahl von Feldern und denselben Typ aufweist.
Dann können wir bequeme Methoden anwenden wie:
Und wir können diese Technik einfach wie folgt anwenden:
JPA 2.1 mit @SqlResultSetMapping
Mit der Einführung von JPA 2.1 können wir die Annotation @SqlResultSetMapping verwenden, um das Problem zu lösen.
Wir müssen eine Ergebnismengenzuordnung irgendwo in einer Entität deklarieren:
Und dann machen wir einfach:
In diesem Fall
Jedi
muss es sich natürlich nicht um eine zugeordnete Entität handeln. Es kann ein reguläres POJO sein.Verwenden der XML-Zuordnung
Ich bin einer von denen, die das Hinzufügen all dieser
@SqlResultSetMapping
Elemente in meinen Entitäten als ziemlich invasiv empfinden, und ich mag die Definition benannter Abfragen innerhalb von Entitäten besonders nicht. Alternativ mache ich das alles in derMETA-INF/orm.xml
Datei:Und das sind alle Lösungen, die ich kenne. Die letzten beiden sind der ideale Weg, wenn wir JPA 2.1 verwenden können.
quelle
@SqlResultSetMapping
muss in einer Entität platziert werden, da JPA die Metadaten daraus lesen wird. Sie können nicht erwarten, dass JPA Ihre POJOs überprüft. Die Entität, in der Sie das Mapping platzieren, ist irrelevant, möglicherweise diejenige, die mehr mit Ihren POJO-Ergebnissen zusammenhängt. Alternativ könnte die Zuordnung in XML ausgedrückt werden, um die Kopplung mit einer völlig unabhängigen Entität zu vermeiden.@SqlResultSetMapping
es möglicherweise erwähnenswert, dass für dieJedi
Klasse ein Konstruktor mit allen Argumenten erforderlich ist und für die@ColumnResult
Annotation möglicherweise dastype
Attribut für Konvertierungen hinzugefügt werden muss, die möglicherweise nicht implizit sind (ich musstetype = ZonedDateTime.class
für einige Spalten hinzufügen ).Ja, mit JPA 2.1 ist es einfach. Sie haben sehr nützliche Anmerkungen. Sie vereinfachen dein Leben.
Deklarieren Sie zuerst Ihre native Abfrage und dann Ihre Ergebnismengenzuordnung (die die Zuordnung der von der Datenbank an Ihre POJOs zurückgegebenen Daten definiert). Schreiben Sie Ihre POJO-Klasse, auf die Sie sich beziehen möchten (der Kürze halber hier nicht enthalten). Last but not least: Erstellen Sie beispielsweise eine Methode in einem DAO, um die Abfrage aufzurufen. Dies funktionierte bei mir in einer Dropwizard (1.0.0) App.
Deklarieren Sie zuerst eine native Abfrage in einer Entitätsklasse:
Darunter können Sie die Deklaration der Ergebnismengenzuordnung hinzufügen:
Später in einem DAO können Sie auf die Abfrage als verweisen
Das ist es.
quelle
Wenn Sie verwenden
Spring-jpa
, ist dies eine Ergänzung zu den Antworten und dieser Frage. Bitte korrigieren Sie dies bei Fehlern. Ich habe hauptsächlich drei Methoden verwendet, um ein "Mapping-ErgebnisObject[]
für ein Pojo" zu erzielen, basierend auf dem praktischen Bedarf, den ich erfülle:sql
mit seinerEntity
sind genug.Die ersteren 2 sind fehlgeschlagen, und ich muss a verwenden
nativeQuery
. Hier sind die Beispiele. Das Pojo erwartet:Methode 1 : Ändern Sie das Pojo in eine Schnittstelle:
Und Repository:
Methode 2 : Repository:
Hinweis: Die Parameterfolge des POJO-Konstruktors muss sowohl in der POJO-Definition als auch in SQL identisch sein.
Methode 3 : Verwenden Sie
@SqlResultSetMapping
und@NamedNativeQuery
inEntity
als Beispiel in Edwin Dalorzos Antwort.Die ersten beiden Methoden rufen viele In-the-Middle-Handler auf, z. B. angepasste Konverter. Definiert beispielsweise
AntiStealing
asecretKey
, bevor es beibehalten wird, wird ein Konverter eingefügt, um es zu verschlüsseln. Dies würde dazu führen, dass die ersten beiden Methoden ein konvertiertes Back zurückgeben,secretKey
was nicht das ist, was ich will. Während die Methode 3 den Konverter überwinden und zurückgegebensecretKey
würde, wäre sie dieselbe wie die gespeicherte (eine verschlüsselte).quelle
Das Entpacken kann durchgeführt werden, um Ergebnisse einer Nicht-Entität (dh Beans / POJO) zuzuweisen. Das Verfahren ist wie folgt.
Die Verwendung erfolgt für die Implementierung von JPA-Hibernate.
quelle
JobDTO
dass der Standardkonstruktor vorhanden sein sollte. Oder Sie implementieren Ihren eigenen Transformator basierend auf derAliasToBeanResultTransformer
Implementierung.Deklarieren Sie zunächst folgende Anmerkungen:
Kommentieren Sie dann Ihr POJO wie folgt:
Dann schreiben Sie Annotation Processor:
Verwenden Sie das obige Framework wie folgt:
quelle
BeanUtils
?Der einfachste Weg ist, solche Projektionen zu verwenden . Es kann Abfrageergebnisse direkt Schnittstellen zuordnen und ist einfacher zu implementieren als SqlResultSetMapping.
Ein Beispiel ist unten gezeigt:
Die Felder der projizierten Schnittstelle müssen mit den Feldern in dieser Entität übereinstimmen. Andernfalls kann die Feldzuordnung unterbrochen werden.
Wenn Sie die
SELECT table.column
Notation verwenden, definieren Sie immer Aliase, die mit den Namen der Entität übereinstimmen, wie im Beispiel gezeigt.quelle
Im Ruhezustand können Sie diesen Code verwenden, um Ihre native Abfrage einfach zuzuordnen.
quelle
Verwenden des Ruhezustands:
quelle
Alter Stil mit ResultSet
quelle
Da andere bereits alle möglichen Lösungen erwähnt haben, teile ich meine Problemumgehungslösung.
In meiner Situation mit
Postgres 9.4
, während ich arbeite mitJackson
,Ich bin sicher, dass Sie dasselbe für andere Datenbanken finden können.
Auch FYI, JPA 2.0 native Abfrageergebnisse als Karte
quelle
Ich bin mir nicht sicher, ob dies hier passt, aber ich hatte eine ähnliche Frage und fand folgende einfache Lösung / Beispiel für mich:
In meinem Fall musste ich SQL-Teile verwenden, die in Strings an einer anderen Stelle definiert waren, damit ich nicht nur NamedNativeQuery verwenden konnte.
quelle
Alter Stil mit Resultset
quelle
Wir haben das Problem folgendermaßen gelöst:
quelle
Im folgenden Beispiel wird ein POJO als Pseudoentität zum Abrufen von Ergebnissen aus nativen Abfragen ohne Verwendung von komplexem SqlResultSetMapping verwendet. Benötigen Sie nur zwei Anmerkungen, eine nackte @Enity und eine Dummy-@Id in Ihrem POJO. @Id kann für jedes Feld Ihrer Wahl verwendet werden. Ein @ ID-Feld kann doppelte Schlüssel, aber keine Nullwerte enthalten.
Da @Enity keiner physischen Tabelle zugeordnet ist, wird dieses POJO als Pseudoentität bezeichnet.
Umgebung: eclipselink 2.5.0-RC1, jpa-2.1.0, mysql-connector-java-5.1.14
Sie können das komplette Maven-Projekt hier herunterladen
Die native Abfrage basiert auf MySQL-Beispielmitarbeitern db http://dev.mysql.com/doc/employee/en/employees-installation.html
persistence.xml
Employee.java
EmployeeNativeQuery.java
quelle
list
es sich angeblich um eine Liste handeltEmployee
, warum iteriert Ihre for-each-Schleife über einen TypObject
? Wenn Sie Ihre for-each-Schleife so schreiben, als würdenfor(Employee emp : list)
Sie feststellen, dass Ihre Antwort falsch ist und der Inhalt Ihrer Liste keine Mitarbeiter sind und dass diese von Ihnen unterdrückte Warnung den Zweck hatte, Sie auf diesen möglichen Fehler aufmerksam zu machen.List<Employee> list = (List<Employee>) query.getResultList();
Ändernfor (Object emp : list)
in"for (Employee emp : list)
besser ist, aber keine Fehler, wenn sie beibehalten wird,Object emp
da "Liste" eine Instanz von istList<Employee>
. Ich habe den Code in Git Project geändert, aber nicht hier, um Ihren Kommentar für den ursprünglichen Beitrag relevant zu haltenQuery query = em.createNativeQuery("select * ...", Employee.class);
und persistence.xml an, die native Abfrage gibt eine Liste der Mitarbeiter zurück. Ich habe gerade das Projekt ohne Problem ausgecheckt und ausgeführt. Wenn Sie MySQL-Beispielmitarbeiter db lokal einrichten, sollten Sie auch in der Lage sein, das Projekt auszuführenEmployee
eine Entität ist, von der ich annehme, dass sie eine Entität ist. Ist es nicht?Wenn Sie Spring verwenden, können Sie verwenden
org.springframework.jdbc.core.RowMapper
Hier ist ein Beispiel:
quelle
Verwenden des Ruhezustands:
quelle
Einfache Möglichkeit zum Konvertieren einer SQL-Abfrage in eine POJO-Klassensammlung.
quelle
Sie benötigen lediglich ein DTO mit einem Konstruktor:
und nenne es:
quelle
Verwenden Sie
DTO Design Pattern
. Es wurde in verwendetEJB 2.0
. Die Entität wurde von einem Container verwaltet.DTO Design Pattern
wird verwendet, um dieses Problem zu lösen. Es kann jedoch jetzt verwendet werden, wenn die Anwendung entwickeltServer Side
undClient Side
separat erstellt wird.DTO
wird verwendet, wennServer side
nichtEntity
mit Annotation an übergeben / zurückgegeben werden sollClient Side
.DTO-Beispiel:
PersonEntity.java
PersonDTO.java
DTOBuilder.java
EntityBuilder.java <- es muss sein
quelle