【问题标题】:How to return a list of specific type instead of List<Object[]> in Hibernate?如何在 Hibernate 中返回特定类型的列表而不是 List<Object[]>?
【发布时间】:2012-06-05 10:48:33
【问题描述】:

我有类树:

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&lt;Object[]&gt;

是否可以将返回的数据强制转换为以下类:

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 这就是你要找的东西吗?
  • 没有。查询返回 List,但我希望该查询返回 List

标签: java hibernate casting hql


【解决方案1】:

如果您使用 Hibernate 5.x,则可以使用 ResultTransformer,例如,如 in this blog post 所述。请注意,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 的新方法
【解决方案2】:

我有同样的问题..我写了这个查询

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




}

【讨论】:

    【解决方案3】:

    JPA 查询中有不同类型的选择。 你目前使用的是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. 自定义类必须有一个构造函数,该构造函数采用您在查询字符串中定义的结果值。

    Read more on selects in JPA2 queries.

    【讨论】:

    • 感谢您的准确回答!为了使答案更加准确,我想指出构造函数名称必须是完全限定的,并且reserved words in your package name can lead to problems
    • 我正在使用共享会话契约,所以我没有 entityManager 对象。无论如何要解决这个问题?
    【解决方案4】:

    你可以使用 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(); 
    

    【讨论】:

    • 这种返回类型仅适用于单值选择。 JPA 文档说:The select list of the query must contain only a single item, which must be assignable to the type specified by the resultClass argument。并且休眠消息来源说"Cannot create TypedQuery for query with more than one return using requested result type [" + resultClass.getName() + "]"。所以基本上它会抛出 IllegalArgumentException - 如果发现查询字符串无效或发现查询结果不能分配给指定类型
    【解决方案5】:

    如果你真的确定你可以进行类型转换。

     List<classD> newlist = ...;
     for(Object o : list){
          newlist.add((classD) o);
     }
    

    请注意这一点

    所以是的。手动铸造。 (注:带数组(可以直接投)

    【讨论】:

    • 列表不是 List 的类型吗?我不明白,你的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-07-11
    • 1970-01-01
    • 2019-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-20
    相关资源
    最近更新 更多