91 votes

Quelle est la "bonne" façon de convertir Hibernate Query.list() en List<Type> ?

Je suis un débutant avec Hibernate et j'écris une méthode simple pour retourner une liste d'objets. correspondant à un filtre spécifique. List<Foo> semblait un type de retour naturel.

Quoi que je fasse, je n'arrive pas à rendre le compilateur heureux, à moins d'employer un vilain @SuppressWarnings .

import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;

public class Foo {

    public Session acquireSession() {
        // All DB opening, connection etc. removed,
        // since the problem is in compilation, not at runtime.
        return null;
    }

    @SuppressWarnings("unchecked") /* <----- */

    public List<Foo> activeObjects() {
        Session s = acquireSession();
        Query   q = s.createQuery("from foo where active");
        return (List<Foo>) q.list();
    }
}

Je voudrais me débarrasser de ça SuppressWarnings . Mais si je le fais, je reçois l'avertissement

Warning: Unchecked cast from List to List<Foo>

(je peux l'ignorer, mais j'aimerais ne pas l'avoir en premier lieu), et si je supprime le générique pour me conformer à la norme .list() le type de retour, je reçois l'avertissement

Warning: List is a raw type. References to generic type List<E>
should be parameterized.

J'ai remarqué que org.hibernate.mapping fait déclarer un List ; mais c'est un tout autre type - Query renvoie un java.util.List comme un type brut. Je trouve étrange qu'un Hibernate récent (4.0.x) n'implémente pas les types paramétrés, je soupçonne donc que c'est moi qui fais plutôt quelque chose de mal.

Il ressemble beaucoup à Conversion du résultat d'Hibernate en une liste d'objets Mais ici, je n'ai pas d'erreur "dure" (le système connaît le type Foo, et je n'utilise pas une SQLQuery mais une simple Query). Donc pas de joie.

J'ai également examiné Hibernate Class Cast Exception parce qu'il avait l'air prometteur, mais ensuite j'ai réalisé que j'ai no obtenir des Exception ... mon problème est simplement celui d'un avertissement - un style de codage, si vous voulez.

La documentation sur jboss.org, les manuels d'Hibernate et plusieurs tutoriels ne semblent pas couvrir le sujet en tel (ou je n'ai pas cherché dans les bons endroits ?). Lorsqu'ils entrent dans les détails, ils utilisent le moulage à la volée - et ceci sur des tutoriels qui n'étaient pas sur le site officiel jboss.org, donc je suis un peu méfiant.

Le code, une fois compilé, s'exécute sans aucune apparent problème... que je sache... pour le moment ; et les résultats sont ceux attendus.

Alors : est-ce que je fais bien les choses ? Est-ce que je rate quelque chose d'évident ? Existe-t-il une méthode "officielle" ou "recommandé" La manière de le faire ?

3voto

Popa Andrei Points 47

La seule façon de fonctionner pour moi était avec un Iterator.

Iterator iterator= query.list().iterator();
Destination dest;
ArrayList<Destination> destinations= new ArrayList<>();
Iterator iterator= query.list().iterator();
    while(iterator.hasNext()){
        Object[] tuple= (Object[]) iterator.next();
        dest= new Destination();
        dest.setId((String)tuple[0]);
        dest.setName((String)tuple[1]);
        dest.setLat((String)tuple[2]);
        dest.setLng((String)tuple[3]);
        destinations.add(dest);
    }

Avec les autres méthodes que j'ai trouvées, j'ai eu des problèmes de fonte.

2voto

lakreqta Points 49

Vous utilisez un ResultTransformer comme ça :

public List<Foo> activeObjects() {
    Session s = acquireSession();
    Query   q = s.createQuery("from foo where active");
    q.setResultTransformer(Transformers.aliasToBean(Foo.class));
    return (List<Foo>) q.list();
}

0voto

ANTARA Points 38

La bonne méthode consiste à utiliser les transformateurs d'hibernation :

public class StudentDTO {
private String studentName;
private String courseDescription;

public StudentDTO() { }  
...
} 

.

List resultWithAliasedBean = s.createSQLQuery(
"SELECT st.name as studentName, co.description as courseDescription " +
"FROM Enrolment e " +
"INNER JOIN Student st on e.studentId=st.studentId " +
"INNER JOIN Course co on e.courseCode=co.courseCode")
.setResultTransformer( Transformers.aliasToBean(StudentDTO.class))
.list();

StudentDTO dto =(StudentDTO) resultWithAliasedBean.get(0);

L'itération à travers les Object[] est redondante et aurait un impact négatif sur les performances. Vous trouverez des informations détaillées sur l'utilisation des transofrmers ici : Transformateurs pour HQL et SQL

Si vous recherchez une solution encore plus simple, vous pouvez utiliser out-of-the-box-map-transformer :

List iter = s.createQuery(
"select e.student.name as studentName," +
"       e.course.description as courseDescription" +
"from   Enrolment as e")
.setResultTransformer( Transformers.ALIAS_TO_ENTITY_MAP )
.iterate();

String name = (Map)(iter.next()).get("studentName");

0voto

Laxman G Points 1272

J'utilise juste Transformers Cela n'a pas fonctionné pour moi, je recevais des exceptions de type cast.

sqlQuery.setResultTransformer(Transformers.aliasToBean(MYEngityName.class)) n'a pas fonctionné parce que j'obtenais un tableau d'objets dans l'élément de liste de retour et non le type fixe MYEngityName de l'élément de liste.

Cela a fonctionné pour moi quand j'ai fait les changements suivants Quand j'ai ajouté sqlQuery.addScalar(-) chaque colonne sélectionnée et son type et pour une colonne spécifique de type String, nous ne devons pas mapper son type, comme par exemple addScalar("langCode");

Et j'ai joint MYEngityName avec NextEnity, nous ne pouvons pas simplement select * dans la requête, cela donnera un tableau d'objets dans la liste de retour.

Exemple de code ci-dessous :

session = ht.getSessionFactory().openSession();
                String sql = new StringBuffer("Select txnId,nft.mId,count,retryReason,langCode FROM  MYEngityName nft INNER JOIN NextEntity m on nft.mId  =  m.id where nft.txnId < ").append(lastTxnId)
                       .append(StringUtils.isNotBlank(regionalCountryOfService)? " And  m.countryOfService in ( "+ regionalCountryOfService +" )" :"")
                       .append(" order by nft.txnId desc").toString();
                SQLQuery sqlQuery = session.createSQLQuery(sql);
                sqlQuery.setResultTransformer(Transformers.aliasToBean(MYEngityName.class));
                sqlQuery.addScalar("txnId",Hibernate.LONG)
                        .addScalar("merchantId",Hibernate.INTEGER)
                        .addScalar("count",Hibernate.BYTE)
                        .addScalar("retryReason")
                        .addScalar("langCode");
                sqlQuery.setMaxResults(maxLimit);
                return sqlQuery.list();

Cela pourrait aider quelqu'un. De cette façon, ça marche pour moi.

0voto

Ricardo Terra Points 61

Dans un projet où je suis consultant, j'ai rencontré ce problème. Voir la solution :
Tout d'abord, j'ai créé la méthode suivante :

protected <T> MyTypedQuery<T> createNamedAliasQuery(final String queryName, final Class<T> type) {  
    final Query q = getSafeEntityManager().createNamedQuery(queryName);
    q.unwrap(org.hibernate.Query.class)
        .setResultTransformer(Transformers.aliasToBean(type));  
    return new MyTypedQuery<T>(q); 
}

Ensuite, je crée un MyTypedQuery, qui ressemble à un wrapper, comme ci-dessous :

public class MyTypedQuery<R> implements TypedQuery<R> {
    private Query q;

    public MyTypedQuery(Query q) {
        this.q = q;
    }

    @Override
    public int executeUpdate() {
        return this.q.executeUpdate();
    }

    @Override
    public int getFirstResult() {
        return this.q.getFirstResult();
    }

    @Override
    public FlushModeType getFlushMode() {
        return this.q.getFlushMode();
    }

    @Override
    public Map<String, Object> getHints() {
        return this.q.getHints();
    }

    @Override
    public LockModeType getLockMode() {
        return this.q.getLockMode();
    }

    @Override
    public int getMaxResults() {
        return this.q.getMaxResults();
    }

    @Override
    public Parameter<?> getParameter(String arg0) {
        return this.q.getParameter(arg0);
    }

    @Override
    public Parameter<?> getParameter(int arg0) {
        return this.q.getParameter(arg0);
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> Parameter<T> getParameter(String arg0, Class<T> arg1) {
        return (Parameter<T>) this.q.getParameter(arg0);
    }

    @Override
    public <T> Parameter<T> getParameter(int arg0, Class<T> arg1) {
        return (Parameter<T>) this.q.getParameter(arg0, arg1);
    }

    @Override
    public <T> T getParameterValue(Parameter<T> arg0) {
        return (T) this.q.getParameterValue(arg0);
    }

    @Override
    public Object getParameterValue(String arg0) {
        return this.q.getParameterValue(arg0);
    }

    @Override
    public Object getParameterValue(int arg0) {
        return this.q.getParameterValue(arg0);
    }

    @Override
    public Set<Parameter<?>> getParameters() {
        return this.q.getParameters();
    }

    @Override
    public boolean isBound(Parameter<?> arg0) {
        return this.q.isBound(arg0);
    }

    @Override
    public <T> T unwrap(Class<T> arg0) {
        return this.q.unwrap(arg0);
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<R> getResultList() {
        return (List<R>) this.q.getResultList();
    }

    @SuppressWarnings("unchecked")
    @Override
    public R getSingleResult() {
        return (R) this.q.getSingleResult();
    }

    @Override
    public TypedQuery<R> setFirstResult(int arg0) {
        this.q.setFirstResult(arg0);
        return this;
    }

    @Override
    public TypedQuery<R> setFlushMode(FlushModeType arg0) {
        this.q.setFlushMode(arg0);
        return this;
    }

    @Override
    public TypedQuery<R> setHint(String arg0, Object arg1) {
        this.q.setHint(arg0, arg1);
        return this;
    }

    @Override
    public TypedQuery<R> setLockMode(LockModeType arg0) {
        this.q.setLockMode(arg0);
        return this;
    }

    @Override
    public TypedQuery<R> setMaxResults(int arg0) {
        this.q.setMaxResults(arg0);
        return this;
    }

    @Override
    public <T> TypedQuery<R> setParameter(Parameter<T> arg0, T arg1) {
        this.q.setParameter(arg0, arg1);
        return this;
    }

    @Override
    public TypedQuery<R> setParameter(String arg0, Object arg1) {
        this.q.setParameter(arg0, arg1);
        return this;
    }

    @Override
    public TypedQuery<R> setParameter(int arg0, Object arg1) {
        this.q.setParameter(arg0, arg1);
        return this;
    }

    @Override
    public TypedQuery<R> setParameter(Parameter<Calendar> arg0, Calendar arg1, TemporalType arg2) {
        this.q.setParameter(arg0, arg1, arg2);
        return this;
    }

    @Override
    public TypedQuery<R> setParameter(Parameter<Date> arg0, Date arg1, TemporalType arg2) {
        this.q.setParameter(arg0, arg1, arg2);
        return this;
    }

    @Override
    public TypedQuery<R> setParameter(String arg0, Calendar arg1, TemporalType arg2) {
        this.q.setParameter(arg0, arg1, arg2);
        return this;
    }

    @Override
    public TypedQuery<R> setParameter(String arg0, Date arg1, TemporalType arg2) {
        this.q.setParameter(arg0, arg1, arg2);
        return this;
    }

    @Override
    public TypedQuery<R> setParameter(int arg0, Calendar arg1, TemporalType arg2) {
        this.q.setParameter(arg0, arg1, arg2);
        return this;
    }

    @Override
    public TypedQuery<R> setParameter(int arg0, Date arg1, TemporalType arg2) {
        this.q.setParameter(arg0, arg1, arg2);
        return this;
    }
}

Troisièmement (et enfin), l'utilisation est simple comme bonjour :

final List<Car> list = 
            createNamedAliasQuery("your-named-query", Car.class)
                .setParameter("idCar", idCar)
                .setParameter("idModel", idModel)
                .getResultList();

Notez que @SuppressWarnings("unchecked") apparaît une fois dans notre MyTypedQuery et non pas à chaque utilisation.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X