
Gunjan Schah
Ich verwende JPA in meinem Projekt.
Ich bin zu einer Abfrage gekommen, in der ich eine Join-Operation für fünf Tabellen durchführen muss. Also habe ich eine native Abfrage erstellt, die fünf Felder zurückgibt.
Jetzt möchte ich das Ergebnisobjekt in die 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 bin zu folgender Lösung gekommen..
@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 jetzt hier in resultClass eine Klasse angeben, die eine tatsächliche JPA-Entität ist? ODER Wir können es in eine beliebige JAVA POJO-Klasse konvertieren, die dieselben Spaltennamen enthält.

Edwin Dalorzo
Ich habe ein paar Lösungen dafür gefunden.
Verwenden von zugeordneten Entitäten (JPA 2.0)
Mit JPA 2.0 ist es nicht möglich, eine native Abfrage einem POJO zuzuordnen, dies kann nur mit einer Entität erfolgen.
Zum Beispiel:
Query query = em.createNativeQuery("SELECT name,age FROM jedi_table", Jedi.class);
@SuppressWarnings("unchecked")
List<Jedi> items = (List<Jedi>) query.getResultList();
Aber in diesem Fall Jedi
muss eine zugeordnete Entitätsklasse sein.
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
@NamedNativeQuery(
name="jedisQry",
query = "SELECT name,age FROM jedis_table",
resultClass = Jedi.class)
Dann können wir einfach tun:
TypedQuery<Jedi> query = em.createNamedQuery("jedisQry", Jedi.class);
List<Jedi> items = query.getResultList();
Dies ist sicherer, aber wir sind immer noch darauf beschränkt, eine zugeordnete Entität zu verwenden.
Manuelle Zuordnung
Eine Lösung, mit der ich ein wenig experimentiert habe (vor der Ankunft von JPA 2.1), war die Zuordnung zu einem POJO-Konstruktor mit ein wenig Reflexion.
public static <T> T map(Class<T> type, Object[] tuple){
List<Class<?>> tupleTypes = new ArrayList<>();
for(Object field : tuple){
tupleTypes.add(field.getClass());
}
try {
Constructor<T> ctor = type.getConstructor(tupleTypes.toArray(new Class<?>[tuple.length]));
return ctor.newInstance(tuple);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Diese Methode nimmt grundsätzlich ein Tupel-Array (wie es von nativen Abfragen zurückgegeben wird) und ordnet es einer bereitgestellten POJO-Klasse zu, indem sie nach einem Konstruktor sucht, der dieselbe Anzahl von Feldern und denselben Typ hat.
Dann können wir bequeme Methoden verwenden wie:
public static <T> List<T> map(Class<T> type, List<Object[]> records){
List<T> result = new LinkedList<>();
for(Object[] record : records){
result.add(map(type, record));
}
return result;
}
public static <T> List<T> getResultList(Query query, Class<T> type){
@SuppressWarnings("unchecked")
List<Object[]> records = query.getResultList();
return map(type, records);
}
Und wir können diese Technik einfach wie folgt anwenden:
Query query = em.createNativeQuery("SELECT name,age FROM jedis_table");
List<Jedi> jedis = getResultList(query, Jedi.class);
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 irgendwo in einer Entität ein Resultset-Mapping deklarieren:
@SqlResultSetMapping(name="JediResult", classes = {
@ConstructorResult(targetClass = Jedi.class,
columns = {@ColumnResult(name="name"), @ColumnResult(name="age")})
})
Und dann machen wir einfach:
Query query = em.createNativeQuery("SELECT name,age FROM jedis_table", "JediResult");
@SuppressWarnings("unchecked")
List<Jedi> samples = query.getResultList();
In diesem Fall natürlich Jedi
muss keine zugeordnete Entität sein. Es kann ein normales POJO sein.
Verwenden von XML-Mapping
Ich bin einer von denen, die all dies hinzufügen @SqlResultSetMapping
ziemlich invasiv in meinen Entitäten, und ich mag besonders die Definition von benannten Abfragen innerhalb von Entitäten nicht, also mache ich das alles alternativ in der META-INF/orm.xml
Datei:
<named-native-query name="GetAllJedi" result-set-mapping="JediMapping">
<query>SELECT name,age FROM jedi_table</query>
</named-native-query>
<sql-result-set-mapping name="JediMapping">
<constructor-result target-class="org.answer.model.Jedi">
<column name="name" class="java.lang.String"/>
<column name="age" class="java.lang.Integer"/>
</constructor-result>
</sql-result-set-mapping>
Und das sind alle Lösungen, die ich kenne. Die letzten beiden sind der ideale Weg, wenn wir JPA 2.1 verwenden können.

Denis Tulsky
JPA bietet eine SqlResultSetMapping
Dadurch können Sie alle Rückgaben Ihrer nativen Abfrage einer Entität zuordnen oder eine benutzerdefinierte Klasse.
BEARBEITEN JPA 1.0 erlaubt keine Zuordnung zu Nicht-Entitätsklassen. Nur in JPA 2.1 a KonstruktorErgebnis wurde hinzugefügt, um Rückgabewerte einer Java-Klasse zuzuordnen.
Auch für das Problem von OP mit dem Abrufen der Anzahl sollte es ausreichen, eine Ergebnismengenzuordnung mit einer einzigen zu definieren ColumnResult

GiulioDS
Ja, mit JPA 2.1 ist es einfach. Sie haben sehr nützliche Anmerkungen. Sie vereinfachen Ihr Leben.
Deklarieren Sie zuerst Ihre native Abfrage, dann Ihre Ergebnismengenzuordnung (die die Zuordnung der von der Datenbank zurückgegebenen Daten zu Ihren POJOs 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 eine Methode in einem DAO (z. B.), um die Abfrage aufzurufen. Dies hat bei mir in einer Dropwizard-App (1.0.0) funktioniert.
Deklarieren Sie zuerst eine native Abfrage in einer Entitätsklasse:
@NamedNativeQuery (
name = "domain.io.MyClass.myQuery",
query = "Select a.colA, a.colB from Table a",
resultSetMapping = "mappinMyNativeQuery") // must be the same name as in the SqlResultSetMapping declaration
Darunter können Sie die Resultset-Mapping-Deklaration hinzufügen:
@SqlResultSetMapping(
name = "mapppinNativeQuery", // same as resultSetMapping above in NativeQuery
classes = {
@ConstructorResult(
targetClass = domain.io.MyMapping.class,
columns = {
@ColumnResult( name = "colA", type = Long.class),
@ColumnResult( name = "colB", type = String.class)
}
)
}
)
Später in einem DAO können Sie auf die Abfrage verweisen als
public List<domain.io.MyMapping> findAll() {
return (namedQuery("domain.io.MyClass.myQuery").list());
}
Das ist es.

Tina
Wenn du benutzt Spring-jpa
, dies ist eine Ergänzung zu den Antworten und dieser Frage. Bitte korrigieren Sie dies, falls Fehler vorhanden sind. Ich habe hauptsächlich drei Methoden verwendet, um ein “Mapping-Ergebnis” zu erzielen Object[]
to a pojo”, basierend auf dem praktischen Bedürfnis, das ich erfülle:
- Die eingebaute JPA-Methode reicht aus.
- Die integrierte JPA-Methode reicht nicht aus, sondern eine angepasste
sql
mit Entity
sind genug.
-
Die ersteren 2 sind fehlgeschlagen, und ich muss a verwenden nativeQuery
. Hier sind die Beispiele. Das erwartete Pojo:
public class Antistealingdto {
private String secretKey;
private Integer successRate;
// GETTERs AND SETTERs
public Antistealingdto(String secretKey, Integer successRate) {
this.secretKey = secretKey;
this.successRate = successRate;
}
}
Methode 1: Ändern Sie das Pojo in eine Schnittstelle:
public interface Antistealingdto {
String getSecretKey();
Integer getSuccessRate();
}
Und Depot:
interface AntiStealingRepository extends CrudRepository<Antistealing, Long> {
Antistealingdto findById(Long id);
}
Methode 2: Repository:
@Query("select new AntistealingDTO(secretKey, successRate) from Antistealing where ....")
Antistealing whatevernamehere(conditions);
Hinweis: Die Parametersequenz des POJO-Konstruktors muss sowohl in der POJO-Definition als auch in SQL identisch sein.
Methode 3: Verwenden @SqlResultSetMapping
und @NamedNativeQuery
in Entity
wie das Beispiel in Edwin Dalorzos Antwort.
Die ersten beiden Methoden würden viele In-the-Middle-Handler aufrufen, z. B. angepasste Konverter. Zum Beispiel, AntiStealing
definiert a secretKey
, 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 Zurück zurückgeben secretKey
was ich nicht will. Während die Methode 3 den Konverter überwinden und zurückkehren würde secretKey
wäre dasselbe, wie es gespeichert ist (ein verschlüsseltes).
Die Unwrap-Prozedur kann durchgeführt werden, um Ergebnisse einer Nicht-Entität (das ist Beans/POJO) zuzuweisen. Das Verfahren ist wie folgt.
List<JobDTO> dtoList = entityManager.createNativeQuery(sql)
.setParameter("userId", userId)
.unwrap(org.hibernate.Query.class).setResultTransformer(Transformers.aliasToBean(JobDTO.class)).list();
Die Verwendung dient der JPA-Hibernate-Implementierung.

Thanthu
Der einfachste Weg ist, so zu verwenden Projektionen. Es kann Abfrageergebnisse direkt Schnittstellen zuordnen und ist einfacher zu implementieren als die Verwendung von SqlResultSetMapping.
Ein Beispiel ist unten gezeigt:
@Repository
public interface PeopleRepository extends JpaRepository<People, Long> {
@Query(value = "SELECT p.name AS name, COUNT(dp.people_id) AS count " +
"FROM people p INNER JOIN dream_people dp " +
"ON p.id = dp.people_id " +
"WHERE p.user_id = :userId " +
"GROUP BY dp.people_id " +
"ORDER BY p.name", nativeQuery = true)
List<PeopleDTO> findByPeopleAndCountByUserId(@Param("userId") Long userId);
@Query(value = "SELECT p.name AS name, COUNT(dp.people_id) AS count " +
"FROM people p INNER JOIN dream_people dp " +
"ON p.id = dp.people_id " +
"WHERE p.user_id = :userId " +
"GROUP BY dp.people_id " +
"ORDER BY p.name", nativeQuery = true)
Page<PeopleDTO> findByPeopleAndCountByUserId(@Param("userId") Long userId, Pageable pageable);
}
// Interface to which result is projected
public interface PeopleDTO {
String getName();
Long getCount();
}
Die Felder der projizierten Schnittstelle müssen mit Feldern in dieser Entität übereinstimmen. Andernfalls könnte die Feldzuordnung brechen.
Auch wenn Sie verwenden SELECT table.column
Notation definiert immer Aliase, die mit Namen von Entitäten übereinstimmen, wie im Beispiel gezeigt.

Yaswant raju Vysyaraju
Im Ruhezustand können Sie diesen Code verwenden, um Ihre native Abfrage einfach zuzuordnen.
private List < Map < String, Object >> getNativeQueryResultInMap() {
String mapQueryStr = "SELECT * FROM AB_SERVICE three ";
Query query = em.createNativeQuery(mapQueryStr);
NativeQueryImpl nativeQuery = (NativeQueryImpl) query;
nativeQuery.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
List < Map < String, Object >> result = query.getResultList();
for (Map map: result) {
System.out.println("after request ::: " + map);
}
return result;}
9160700cookie-checkJPA : So konvertieren Sie eine Ergebnismenge einer nativen Abfrage in eine POJO-Klassensammlungyes
Überprüfen Sie diese Antwort. Es hat eine vollständige Antwort: stackoverflow.com/a/50365522/3073945
– Md. Sajedul Karim
16. Mai 2018 um 8:36 Uhr
er benutzt jpa, nicht spring
– ihm
18. Oktober 2018 um 0:21 Uhr