Je crée une requête complexe avec plusieurs tables et je dois répertorier le résultat. En général, j'utilise la variable EntityManager
et mappe le résultat sur la représentation JPA:
UserEntity user = em.find(UserEntity.class, "5");
Ensuite, je peux accéder à toutes les valeurs comme le définit la classe utilisateur UserEntity
. Mais comment puis-je accéder aux valeurs de champ renvoyées par une requête native à tables multiples? Ce que je reçois est une liste d'objets. C'est bien jusqu'à présent, mais quel "est" cet objet? Tableau? Carte? Collection? ...
//simpleExample
Query query = em.createNativeQuery("SELECT u.name,s.something FROM user u, someTable s WHERE s.user_id = u.id");
List list = query.getResultList();
//do sth. with the list, for example access "something" for every result row.
Je suppose que la réponse est assez simple, mais la plupart des exemples ne montrent que l’utilisation lorsqu’elle est directement transmise à une cible.
PS: Dans l'exemple, je pourrais bien sûr utiliser les mappages de classes. Mais dans mon cas, someTable
n'est pas géré par JPA, et par conséquent, je n'ai ni l'entité ni la représentation en classe de celui-ci, et comme je rejoins à peu près 20 tables, je ne veux pas créer tous les classes juste pour accéder aux valeurs.
La règle générale est la suivante:
select
contient une expression unique et qu'il s'agit d'une entité, alors le résultat est cette entité.select
contient une expression unique et qu'il s'agit d'une primitive, alors le résultat est cette primitive.select
contient plusieurs expressions, le résultat est Object[]
contenant les primitives/entités correspondantes.Donc, dans votre cas, list
est un List<Object[]>
.
Depuis JPA 2.0, une TypedQuery
peut être utilisée:
TypedQuery<SimpleEntity> q =
em.createQuery("select t from SimpleEntity t", SimpleEntity.class);
List<SimpleEntity> listOfSimpleEntities = q.getResultList();
for (SimpleEntity entity : listOfSimpleEntities) {
// do something useful with entity;
}
La requête ci-dessus renvoie la liste des objets []. Donc, si vous voulez obtenir le nom d'utilisateur et quelque chose de la liste, vous devez itérer et convertir ces valeurs pour les classes correspondantes.
Si vous avez besoin d'un moyen plus pratique d'accéder aux résultats, il est possible de transformer le résultat d'une requête SQL arbitrairement complexe en une classe Java avec un minimum de tracas:
Query query = em.createNativeQuery("select 42 as age, 'Bob' as name from dual",
MyTest.class);
MyTest myTest = (MyTest) query.getResultList().get(0);
assertEquals("Bob", myTest.name);
La classe doit être déclarée @Entity, ce qui signifie que vous devez vous assurer qu'elle possède un @Id unique.
@Entity
class MyTest {
@Id String name;
int age;
}
Voici l'échantillon sur ce qui a fonctionné pour moi. Je pense que cette méthode est nécessaire dans la classe entity pour mapper les colonnes SQL avec les attributs de classe Java.
//simpleExample
Query query = em.createNativeQuery(
"SELECT u.name,s.something FROM user u, someTable s WHERE s.user_id = u.id",
NameSomething.class);
List list = (List<NameSomething.class>) query.getResultList();
Classe d'entité:
@Entity
public class NameSomething {
@Id
private String name;
private String something;
// getters/setters
/**
* Generic put method to map JPA native Query to this object.
*
* @param column
* @param value
*/
public void put(Object column, Object value) {
if (((String) column).equals("name")) {
setName(String) value);
} else if (((String) column).equals("something")) {
setSomething((String) value);
}
}
}