web-dev-qa-db-fra.com

JPA Native Query sélectionne et diffuse l'objet

J'ai un objet Admin qui étend User. Par défaut, les deux objets se trouvent dans la table User_ de ma base de données Derby (champs inclus de Admin). Normalement, je choisirais une User comme ceci:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root user= query.from(User.class);
Predicate predicateId = cb.equal(category.get("id"), id);
query.select(user).where(predicateId);
return em.createQuery(query).getSingleResult();

Cependant, en raison de la complexité de ma requête, j'utilise une requête native comme celle-ci:

Query query = em.createNativeQuery("SELECT USER.* FROM USER_ AS USER WHERE ID = ?");
query.setParameter(1, id);
return (User) query.getSingleResult();

Bien que cela jette une exception de casting. Je suppose que cela est dû aux champs de Admin.

Ma question est la suivante: comment sélectionner une User en utilisant une requête native avec un résultat identique à celui du premier exemple (y compris les mêmes valeurs pour @LOB et @ManyToOne (et cetera) que la requête JPQL renverrait)?

19
Menno

Vous voudrez peut-être essayer l'une des méthodes suivantes:

  • En utilisant la méthode createNativeQuery(sqlString, resultClass)

    Les requêtes natives peuvent également être définies de manière dynamique à l'aide de l'API EntityManager.createNativeQuery().

    String sql = "SELECT USER.* FROM USER_ AS USER WHERE ID = ?";
    
    Query query = em.createNativeQuery(sql, User.class);
    query.setParameter(1, id);
    User user = (User) query.getSingleResult();
    
  • En utilisant l'annotation @NamedNativeQuery

    Les requêtes natives sont définies à l'aide des annotations @NamedNativeQuery et @NamedNativeQueries Ou de l'élément XML <named-native-query>.

    @NamedNativeQuery(
        name="complexQuery",
        query="SELECT USER.* FROM USER_ AS USER WHERE ID = ?",
        resultClass=User.class
    )
    public class User { ... }
    
    Query query = em.createNamedQuery("complexQuery", User.class);
    query.setParameter(1, id);
    User user = (User) query.getSingleResult();
    

Vous pouvez en lire plus dans l'excellent livre ouvert Java Persistence (disponible dans PDF ).

───────
NOTE: En ce qui concerne l'utilisation de getSingleResult(), voir Pourquoi vous ne devriez jamais utiliser getSingleResult() dans JPA .

45
Paul Vargas

Veuillez vous référer à JPA: comment convertir un jeu de résultats de requête natif en collection de classes POJO

Pour Postgres 9.4,

List<String> list = em.createNativeQuery("select cast(row_to_json(u) as text) from myschema.USER_ u WHERE ID = ?")
                   .setParameter(1, id).getResultList();

User map = new ObjectMapper().readValue(list.get(0), User.class);
2
Darshan Patel

La réponse acceptée est incorrecte.

createNativeQuery retournera toujours un Query:

public Query createNativeQuery(String sqlString, Class resultClass);

L'appel de getResultList sur une Query renvoie List:

List getResultList()

Lors de l'attribution (ou de la conversion) à List<MyEntity>, un avertissement d'attribution non vérifié est généré.

Attendu que, createQuery retournera un TypedQuery:

public <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass);

L'appel de getResultList sur une TypedQuery renvoie List<X>.

List<X> getResultList();

Ceci est correctement typé et ne donnera pas d'avertissement.

Avec createNativeQuery, utiliser ObjectMapper semble être le seul moyen de se débarrasser de l'avertissement. Personnellement, je choisis de supprimer l’avertissement, car j’estime qu’il s’agissait d’une lacune dans la bibliothèque et non d’un problème qui me préoccupe.

0
Derek White