web-dev-qa-db-fra.com

Hibernate SQL Query result Mapping / Convert TO Object / Class / Bean

1 2: sélectionnez (tableau. *)/(Toutes les colonnes) est OK

String sql = "select t_student.* from t_student";
//String sql = "select t_student.id,t_student.name,... from t_student"; //select all column
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(Student.class);//or query.addEntity("alias", Student.class);
//query.list();[Student@..., Student@..., Student@...]
query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP); //or other transformer
query.list(); //[{Student(or alias)=Student@...},{Student=Student@...}]

3: sélectionnez une colonne (pas la totalité), est Erreur

String sql = "select t_student.id,t_student.name.t_student.sex from t_student";
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(Student.class);
query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
query.list(); //Exception:invalid column/no column

Je veux que "3" fonctionne correctement et que le résultat puisse être mappé sur Student.class.
Comme: étudiant [id = ?, nom = ?, sexe = ?, (les autres champs sont nuls/par défaut)]
Je n'ai aucune idée de cette erreur, aidez-moi s'il vous plaît!

12
YETI

Vous pouvez aller plus loin et ajouter .setResultTransformer(Transformers.aliasToBean(YOUR_DTO.class)); et le mapper automatiquement à votre objet dto personnalisé, voir aussi Renvoyer des entités non gérées .

Par exemple:

public List<MessageExtDto> getMessagesForProfile2(Long userProfileId) {
    Query query = getSession().createSQLQuery("  "
            + " select a.*, b.* "
            + " from messageVO AS a "
            + " INNER JOIN ( SELECT max(id) AS id, count(*) AS count FROM messageVO GROUP BY messageConversation_id) as b ON a.id = b.id "
            + " where a.id > 0 "
            + " ")
            .addScalar("id", new LongType())
            .addScalar("message", new StringType())
            ......... your mappings
            .setResultTransformer(Transformers.aliasToBean(MessageExtDto.class));

    List<MessageExtDto> list = query.list();
    return list;
}
23
Paweł Woźniak

Il n'y a que deux façons.

Vous pouvez utiliser le 1er ou le 2e extrait. Selon la documentation Hibernate, vous devez préférer le 2e.

Vous pouvez obtenir juste une liste de tableaux d'objets, comme ceci:

String sql = "select name, sex from t_student";
SQLQuery query = session.createSQLQuery(sql);
query.addScalar("name", StringType.INSTANCE); 
query.addScalar("sex", StringType.INSTANCE); 
query.list();
3
Mikhail Peresypkin

Je veux que "3" fonctionne correctement et que le résultat puisse être mappé sur Student.class

C'est possible en utilisant
Query createNativeQuery(String sqlString, String resultSetMapping)

Dans le deuxième argument, vous pouvez dire le nom du mappage de résultats. Par exemple:

1) Considérons une entité Student , la magie va se trouver dans l'annotation SqlResultSetMapping:

import javax.persistence.Entity;
import javax.persistence.SqlResultSetMapping;
import javax.persistence.Table;

@Entity
@Table(name = "student")
@SqlResultSetMapping(name = "STUDENT_MAPPING", classes = {@ConstructorResult(
    targetClass = Student.class, columns = {
      @ColumnResult(name = "name"),
      @ColumnResult(name = "address")
})})
public class Student implements Serializable {
   private String name;
   private String address;

   /* Constructor for the result mapping; the key is the order of the args*/ 
   public Student(String aName, String anAddress) {
       this.name = aName;
       this.address = anAddress;
   }

   // the rest of the entity
}

2) Vous pouvez maintenant exécuter une requête dont les résultats seront mappés par STUDENT_MAPPING logique:

String query = "SELECT s FROM student s";
String mapping = "STUDENT_MAPPING";
Query query = myEntityManager.createNativeQuery(query, mapping);
@SuppressWarnings("unchecked")
List<Student> students = query.getResultList();
for (Student s : students) {
   s.getName(); // ...
}

Remarque: Je pense qu'il n'est pas possible d'éviter l'avertissement non contrôlé.

3
Manu

J'ai eu le même problème sur HQL Query. J'ai résolu le problème en changeant le transformateur.

Le problème a provoqué la transformation du code écrit en carte. Mais il ne convient pas à Alias ​​Bean. Vous pouvez voir le code d'erreur ci-dessous. Le code écrit pour convertir le résultat en carte et mettre un nouveau champ sur la carte.

Classe: org.hibernate.property.access.internal.PropertyAccessMapImpl.SetterImpl m Méthode: set

    @Override
    @SuppressWarnings("unchecked")
    public void set(Object target, Object value, SessionFactoryImplementor factory) {
        ( (Map) target ).put( propertyName, value );
    }

J'ai résolu le problème pour dupliquer le transformateur et changer le code.

Vous pouvez voir le code dans le projet.

Lien: https://github.com/robeio/robe/blob/DW1.0-migration/robe-hibernate/src/main/Java/io/robe/hibernate/criteria/impl/hql/AliasToBeanResultTransformer. Java

Classe:

import Java.lang.reflect.Field;
import Java.util.Map;

import io.robe.hibernate.criteria.api.query.SearchQuery;
import org.hibernate.HibernateException;
import org.hibernate.transform.AliasedTupleSubsetResultTransformer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class AliasToBeanResultTransformer extends AliasedTupleSubsetResultTransformer {

    private static final Logger LOGGER = LoggerFactory.getLogger(AliasToBeanResultTransformer.class);

    private final Class resultClass;

    // Holds fields of Transform Class as Map. Key is name of field. 
    private Map<String, Field> fieldMap;

    public AliasToBeanResultTransformer(Class resultClass) {
        if ( resultClass == null ) {
            throw new IllegalArgumentException( "resultClass cannot be null" );
        }
        fieldMap = SearchQuery.CacheFields.getCachedFields(resultClass);
        this.resultClass = resultClass;
    }

    @Override
    public boolean isTransformedValueATupleElement(String[] aliases, int tupleLength) {
        return false;
    }

    @Override
    public Object transformTuple(Object[] Tuple, String[] aliases) {
        Object result;
        try {
            result = resultClass.newInstance();
            for ( int i = 0; i < aliases.length; i++ ) {
                String name = aliases[i];
                Field field = fieldMap.get(name);

                if(field == null) {
                    LOGGER.error(name + " field not found in " + resultClass.getName() + " class ! ");
                    continue;
                }
                field.set(result,  Tuple[i]);
            }
        }
        catch ( InstantiationException e ) {
            throw new HibernateException( "Could not instantiate resultclass: " + resultClass.getName() );
        } catch ( IllegalAccessException e ) {
            throw new HibernateException( "Could not instantiate resultclass: " + resultClass.getName() );
        }

        return result;
    }
}

Après avoir créé un nouveau transformateur, vous pouvez utiliser comme ci-dessous.

query.setResultTransformer(new AliasToBeanResultTransformer(YOUR_DTO.class));
1
oopdev