2013-06-28 12 views
11

1 2: (. Tabela *) wybrać/(wszystkie kolumny) jest OKHibernate Query SQL Mapowanie wynik/Konwertuj na obiekt/klasa/Bean

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: wybierz jakąś kolumnę (nie wszyscy), jest błąd

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 

Chcę, aby "3" działało poprawnie, a wynik można odwzorować na Student.class.
Podobno: Student [id = ?, name = ?, sex = ?, (inne pole jest puste/domyślne)]
Nie mam pojęcia o tym błędzie, proszę mi pomóc!

+1

dlaczego używać kwerendy sql? kiedy możesz użyć hql lub kryteriów? wstawiłeś 'hql' zamiast' sql' w 3 pomyłce: P – nachokk

+1

haha! Po prostu pokazuję próbkę. W rzeczywistości, Niektóre biznesy muszą być implementowane przez sql. – YETI

Odpowiedz

3

Istnieją tylko dwa sposoby.

Możesz użyć pierwszego lub drugiego fragmentu. Zgodnie z dokumentacją Hibernate musisz preferować 2nd.

można uzyskać tylko listę tablic obiektów, na przykład:

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

Dziękuję. Użyj query.setResultTransformer ({custom transformator}) po addScalar, możesz przekonwertować do Student.class, ale nie chcę tego w ten sposób. – YETI

+0

Chcę, żeby to była instancja Obiektu Ucznia, czy jest ktoś, kto wie? – YETI

17

Można pójść dalej i dodać .setResultTransformer(Transformers.aliasToBean(YOUR_DTO.class)); i automatycznie na mapę do swojego zwyczaju Dto obiektu, patrz również Returning non-managed entities.

Na przykład:

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

Powinien być przydatny, ale jestem taki leniwy, pomyślałem, że można go przekształcić automatycznie. – YETI

3

chcę "3" do pracy ok, niech wynik może być odwzorowany na Student.class

to możliwe przy użyciu
Query createNativeQuery(String sqlString, String resultSetMapping)

W drugim argumencie można podać nazwę odwzorowania wyniku. Na przykład:

1) rozważmy Student podmiot, magia będzie z adnotacją 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) Teraz można wykonać kwerendy wyniki, które będą odwzorowywane przez STUDENT_MAPPING logika:

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

Uwaga: Myślę, że to nie jest możliwe, aby uniknąć niekontrolowanego ostrzeżenie.

0

Miałem ten sam problem w kwerendzie HQL. Rozwiązałem problem zmieniając transformator.

Problem spowodował, że kod zapisany do przekształcenia jako mapa. Ale nie nadaje się do Alias ​​Bean. Możesz zobaczyć kod błędu poniżej. Kod napisany do rzucenia wyniku jako mapa i umieść nowe pole na mapie.

Klasa: org.hibernate.property.access.internal.PropertyAccessMapImpl.SetterImpl m Metoda: set

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

I rozwiązać problem powielać transformator i zmienić kod.

Możesz zobaczyć kod w projekcie.

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

Klasa:

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

Po stworzył nowy transformator można używać jak poniżej.

query.setResultTransformer(new AliasToBeanResultTransformer(YOUR_DTO.class)); 
Powiązane problemy