Hibernate SQL查询结果映射/转换为对象/类/ Bean

时间:2013-06-28 01:44:57

标签: java sql hibernate hibernate-mapping

1 2:select(table。*)/(all column)没问题

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:选择一些列(不是全部),是错误

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

我希望“3”正常工作,并将结果映射到Student.class 喜欢:学生[id = ?, name =?,sex =?,(其他字段为null /默认)]
我不知道这个错误,请帮帮我!

5 个答案:

答案 0 :(得分:21)

你可以进一步添加 .setResultTransformer(Transformers.aliasToBean(YOUR_DTO.class)); 并自动将其映射到您的自定义dto对象,另请参阅Returning non-managed entities

例如:

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

答案 1 :(得分:3)

只有两种方式。

您可以使用第一个或第二个代码段。根据Hibernate文档,您必须更喜欢2nd。

您只能得到一个对象数组列表,如下所示:

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

答案 2 :(得分:3)

  

我想&#34; 3&#34;工作正常,让结果可以映射到Student.class

可以使用
Query createNativeQuery(String sqlString, String resultSetMapping)

在第二个参数中,您可以告诉结果映射的名称。例如:

1)让我们考虑一个学生实体,魔法将在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)现在您可以执行查询,结果将由STUDENT_MAPPING逻辑映射:

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

注意:我认为无法避免未经检查的警告。

答案 3 :(得分:1)

我在HQL查询上遇到了同样的问题。我通过更换变压器解决了这个问题。

问题导致编写的代码转换为Map。但它不适合Alias Bean。您可以在下面看到错误代码。编写的代码将结果显示为map并将新字段添加到地图中。

类:org.hibernate.property.access.internal.PropertyAccessMapImpl.SetterImpl 米 方法:设置

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

我解决了复制变换器和更改代码的问题。

您可以在项目中看到代码。

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

类别:

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

创建新Transformer之后您可以使用如下所示。

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

答案 4 :(得分:0)

您可以自动映射它:

  1. 您的模型 Student.java

    公开课学生{ 私人字符串名称; 私有字符串地址; }

  2. 存储库

    String sql = "Select * from student"; 查询查询 = em.createNativeQuery(sql, Student.class); List ls = query.getResultList();

  • 所以它会自动将结果映射到 Student 类