如何在Hibernate中返回特定类型的列表而不是List<Object[]>?

14

我有一组类:

classA {  
      classB b;  
      classC c;
      .....
} 

我有这样一个HQL查询:

SELECT a.field1, b.field2, c.field3, c.field4
FROM a LEFT OUTER JOIN b ON a.id = b.fk
       LEFT OUTER JOIN c ON b.id = c.fk 

这个查询返回的是List<Object[]>

能否将返回的数据转换为以下类:

classD {
    Type1 fiedl1;
    Type2 field2;
    Type3 field3;
}

那么在Hibernate中是否可以进行强制类型转换,还是需要手动进行所有的类型转换?


你要的是这个吗?select a from a left outer join b on a.id=b.fk left outer join c on b.id=c.fk - nullpotent
1
查询返回List<Object[]>,但我希望查询返回List<classD>。 - user810430
https://dev59.com/t2Ml5IYBdhLWcg3we3Do - gavenkoa
5个回答

31

在JPA查询中有不同类型的selects。您当前使用的是Array作为返回类型,您需要的是Construct返回类型。以下是如何实现:

String queryStr =
    "select NEW package.YourDefinedCustomClass(
     a.field1, b.field2, c.field3, c.field4) from a left outer join b 
     on a.id=b.fk left outer join c on b.id=c.fk";

TypedQuery<YourDefinedCustomClass> query =
    em.createQuery(queryStr, YourDefinedCustomClass.class);

List<YourDefinedCustomClass> results = query.getResultList();

基本上有两件事:

  1. 自定义类必须是你返回结果的类型
  2. 自定义类必须有一个构造函数,接受你在请求字符串中定义的结果值。

更多关于 JPA2 查询中选择的信息。


谢谢您的准确回答!只是为了让答案更加准确,我想指出构造函数名称必须是完全限定的,而包名中的保留字可能会导致问题。 (参考链接:http://stackoverflow.com/questions/30891824) - naXa stands with Ukraine
我正在使用共享会话合同,因此我没有entityManager对象。有什么解决方法吗? - MarceloBarbosa

2
如果你真的确定可以进行类型转换。
 List<classD> newlist = ...;
 for(Object o : list){
      newlist.add((classD) o);
 }

今日免费次数已满, 请开通会员/明日再来

列表不就是List<Object[]>类型吗?我不理解你的回答。 - d1e

2
您可以使用TypedQuery。
TypedQuery<ClassA> q = em.createQuery("select a from a left outer join b on a.id=b.fk left outer join c on b.id=c.fk", ClassA.class); 
List<ClassA> res = q.getResultList(); 

1
这种返回类型仅适用于单值查询。JPA文档表示:“查询的选择列表必须仅包含一个可分配给resultClass参数指定的类型的项目”。而Hibernate源代码则表示:“无法创建具有多个返回的查询的TypedQuery,使用请求的结果类型[" + resultClass.getName() + "]”。因此,如果发现查询字符串无效或查询结果不能分配给指定的类型,则基本上它会抛出IllegalArgumentException异常。 - d1e

1
如果您使用Hibernate 5.x,可以使用一个ResultTransformer,例如在此博客文章中所述。请注意,ResultTransformer在Hibernate 6中将会被@Deprecated。
应用到您的场景中:
List<classD> classDDTOs = entityManager
.createQuery(
    "SELECT a.field1, b.field2, c.field3, c.field4 " +
    "FROM a LEFT OUTER JOIN b ON a.id = b.fk " +
    "LEFT OUTER JOIN c ON b.id = c.fk")
.unwrap( org.hibernate.query.Query.class )
.setResultTransformer( 
    new ResultTransformer() {
        @Override
        public Object transformTuple(
            Object[] tuple, 
            String[] aliases) {
            return new classD(
                (Type1) tuple[0],
                (Type2) tuple[1],
                (Type3) tuple[1],
            );
        }

        @Override
        public List transformList(List collection) {
            return collection;
        }
    } 
)
.getResultList();

上面的代码假设classD有一个构造函数classD(Type1, Type2, Type3)
这种方法的优点是可以让您定义ResultTransformer一次,并允许您在所有具有相同结果类型的查询中重复使用它。

哇,我得试试这个,但是使用 Hibernate 6 的新方法会怎样呢? - hram908

0

我也遇到了同样的问题...我写了这个查询

Query sqlquery = session.createQuery("select c.courseName,f.facultyID,f.facultyName,f.facultyEmailID,f.facultyContactNo,s.subjectName from com.bean.CourseBean as c,com.bean.FacultyBean as f,com.bean.Faculty_SubjectBean as fs,com.bean.SubjectBean as s where f.facultyID=fs.facultyBean.facultyID AND s.subjectID=fs.subjectBean.subjectID AND c.courseID=f.courseBean.courseID AND collegeid=1");

我返回了一个对象列表,在servlet中我写了以下代码:

java.util.List objList= objFacultyService.listFaculty_sql(1);

java.util.List<Temp> objtemp = new ArrayList<Temp>() ;
for (Object[] objects : objList)
{


        Temp temp = new Temp();
        temp.setFacultyEmailID(objects[3].toString());
        temp.setCourseName(objects[0].toString());
        if(objects[4]==null)
        {
            temp.setFacultyContactNo(1);
        }
        else
        {
                  temp.setFacultyContactNo(Long.parseLong(objects[4].toString()));
        }
        temp.setFacultyID(Long.parseLong(objects[1].toString()));
        temp.setFacultyName(objects[2].toString());
        temp.setSubjectName(objects[5].toString());
        objtemp.add(temp);




}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接