2013-06-28 13 views
11

1 2: (. Tabella *) selezionare/(tutte le colonne) è OKHibernate SQL Query risultato Mapping/Convert to/Oggetto Class/fagioli

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();[[email protected], [email protected], [email protected]] 
query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP); //or other transformer 
query.list(); //[{Student(or alias)[email protected]},{[email protected]}] 

3: selezionare una parte di colonna (non tutti), è Errore

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 

voglio "3" per funzionare bene, e lasciare che il risultato può essere mappato Student.class.
Come: Studente [id = ?, nome =?, Sesso = ?, (altro campo sono null/predefinito)]
Non ho idea di questo errore, aiutatemi per favore!

+1

perché utilizzare query sql? quando puoi usare hql o criteri? metti 'hql' invece di' sql' in 3 un errore: P – nachokk

+1

haha! Ho appena mostrato un campione.Infatti, alcuni affari devono essere implementati da sql. – YETI

risposta

3

Esistono solo due modi.

È possibile utilizzare il primo o il secondo snippet. Secondo la documentazione di Hibernate, devi preferire il secondo.

È possibile ottenere solo un elenco di array di oggetti, in questo modo:

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(); 
+0

Grazie. Utilizzare query.setResultTransformer ({custom transformer}) dopo addScalar, può essere convertito in Student.class, ma non lo voglio in questo modo. – YETI

+0

Voglio che sia un'istanza Object di Student, qualcuno lo sa? – YETI

17

Si può andare oltre e aggiungere .setResultTransformer(Transformers.aliasToBean(YOUR_DTO.class)); e automaticamente mappare alla vostra abitudine dto oggetto, puoi anche Returning non-managed entities.

Ad esempio:

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; 
} 
+3

Dovrebbe essere utile, ma sono così pigro, si pensava che potesse essere trasformato automaticamente. – YETI

3

voglio "3" per funzionare bene, e lasciare che il risultato può essere mappato Student.class

Questo è possibile utilizzando
Query createNativeQuery(String sqlString, String resultSetMapping)

Nel secondo argomento è possibile indicare il nome del mapping dei risultati. Per esempio:

1) Consideriamo un Studente entità, la magia sta per essere nel l'annotazione 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) Ora è possibile eseguire una query i cui risultati verranno mappati da STUDENT_MAPPING logica:

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(); // ... 
} 

Nota: Penso che non è possibile evitare l'avvertimento incontrollato.

0

Ho avuto lo stesso problema su HQL Query. Ho risolto il problema cambiando il trasformatore.

Il problema ha causato la trasformazione del codice scritto in Mappa. Ma non è adatto per Alias ​​Bean. Puoi vedere il codice di errore qui sotto. Il codice scritto per trasmettere risulta come mappa e inserisce un nuovo campo nella mappa.

Classe: org.hibernate.property.access.internal.PropertyAccessMapImpl.SetterImpl m Metodo: Insieme

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

ho risolto il problema per duplicare il trasformatore e modificare il codice.

È possibile visualizzare il codice nel progetto.

Link: 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; 
    } 
} 

Dopo creato nuovo Transformer È possibile utilizzare come qui di seguito.

query.setResultTransformer(new AliasToBeanResultTransformer(YOUR_DTO.class)); 
Problemi correlati