【问题标题】:AliasToBeanResultTransformer and Hibernate SQLQueryAliasToBeanResultTransformer 和 Hibernate SQLQuery
【发布时间】:2010-12-14 06:15:02
【问题描述】:

我有一个相当复杂的查询(HQL 或 Criteria 查询的嵌套级别太多),所以我将其编写为 SQLQuery。我真的很想使用 AliasToBeanResultTransformer 将我的结果转换为列表,但我遇到了一些问题。我已经在我现在所拥有的下面包含了代码 sn-ps。

当我记录转换后查询的结果时,我可以看到转换器确实创建了一个列表,但是,每个 AdvancedClauseSearchResultDTO 中的所有字段都是空的。我认为这意味着我在别名方面做错了...... AliasToBeanResultTransformer 找不到要调用的正确设置器。但是,AdvancedClauseSearchResultDTO 类确实为我在我的 sql 字符串中使用别名的每个列提供了公共设置器。如果这是一个 Criteria 查询,我会使用投影来为要返回的每一列定义一个别名,但我不确定如何使用 SQLQuery 完成同样的事情。

关于如何设置别名以便 ResultTransformer 可以使用它们的任何建议?我看到一些有限的文档表明使用 'as aliasName' 方法应该可以工作,但它似乎不适合我。

从查询字符串定义的 sn-p 开始,注意 'as' 别名定义

StringBuffer clauseBaseQuery = new StringBuffer();
        clauseBaseQuery.append("select ");
        clauseBaseQuery.append(" clauseDetail.clause_detail_id as clauseDetailId,");
        clauseBaseQuery.append(" clauseDetail.clause_id as clauseId,");
        clauseBaseQuery.append(" providers.provider_name as provider, ");
        clauseBaseQuery.append(" products.product_name as product, ");

SQLQuery的创建和resultTransformer的设置

Query query  = session.createSQLQuery(clauseBaseQuery.toString());
query.setResultTransformer(new AdvancedClauseSearchResultTransformer());
return (List<AdvancedClauseSearchResultDTO>)query.list();

AdvancedClauseSearchResultTransformer 类(使用 AliasToBeanResultTransformer 然后做一些额外的处理):

class AdvancedClauseSearchResultTransformer implements ResultTransformer {

        //Use the aliasTransformer to do most of the work
        ResultTransformer aliasTransformer = Transformers.aliasToBean(AdvancedClauseSearchResultDTO.class);

        @Override
        public List transformList(List list) {
            log.debug("transforming CLAUSE results");
            List<AdvancedClauseSearchResultDTO> result = aliasTransformer.transformList(list);
            //for each row, set the status field
           for (AdvancedClauseSearchResultDTO dto : result) {
                log.debug("dto = " + dto);
                String status = null;
                Date effectiveDate = dto.getEffectiveDate();
                Date terminationDate = dto.getTerminationDate();
                Date now = new Date(System.currentTimeMillis());
                if (now.before(effectiveDate)) {
                    status = "Pending";
                } else if (now.after(terminationDate)) {
                    status = "Terminated";
                } else {
                    status = "Active";
                }
                dto.setStatus(status);

                if (StringUtils.isNotEmpty(dto.getReasonForAmendment())){
                    dto.setAmended(Boolean.TRUE);
                }else{
                    dto.setAmended(Boolean.FALSE);
                }
            }

            return result;
        }

        @Override
        public Object transformTuple(Object[] os, String[] strings) {
            Object result = aliasTransformer.transformTuple(os, strings);

            return result;
        }
    }

【问题讨论】:

    标签: java hibernate


    【解决方案1】:

    这取决于您使用的后端,您没有在帖子中提及。

    各种数据库后端对列使用不区分大小写的命名除非您正确地将它们转义,因此即使您使用正确的案例。

    使用 PostgreSQL(我也相信 Oracle),您必须像这样编写查询(注意列引用):

    StringBuffer clauseBaseQuery = new StringBuffer();
    clauseBaseQuery.append("select ");
    clauseBaseQuery.append(" clauseDetail.clause_detail_id as \"clauseDetailId\",");
    clauseBaseQuery.append(" clauseDetail.clause_id as \"clauseId\",");
    clauseBaseQuery.append(" providers.provider_name as \"provider\", ");
    clauseBaseQuery.append(" products.product_name as \"product\", ");
    Query query  = session.createSQLQuery(clauseBaseQuery.toString());
    

    如果您还指定了转换,这将允许 Hibernate 正确识别属性并将结果映射到 bean:

    query.setResultTransformer(Transformers.aliasToBean(AdvancedClauseSearchResultDTO.class));
    

    正如@zinan.yumak 所建议的那样。

    【讨论】:

    • 您还需要引用 DB2 中的别名
    【解决方案2】:

    我今天对此进行了更多研究,终于注意到我得到的潜在错误的良好堆栈跟踪,以及帮助我​​克服这个问题的休眠论坛条目。

    我得到的例外是: 原因:org.hibernate.PropertyNotFoundException:找不到 CLAUSEDETAILID 的设置器

    Hibernate 似乎正在使用我的驼峰式别名并将它们全部转换为大写,因此它无法在我的 AdvancedClauseSearchResultDTO 类中找到匹配的设置器。

    这是为我指明正确方向的论坛条目:

    https://forum.hibernate.org/viewtopic.php?f=1&t=1001608

    我最终为我自己的 ResultTransformer 使用了该帖子中详述的方法,这对我有用。

    【讨论】:

      【解决方案3】:

      我认为写一个结果转换器来解决不是一个好方法 你的问题。试试这样的,

      Query query  = session.createSQLQuery(clauseBaseQuery.toString());
      query.setResultTransformer(Transformers.aliasToBean(AdvancedClauseSearchResultDTO.class));
      

      并且在 AdvancedClauseSearchResultDTO 类中,修改 setter 方法设置为 required 给你的字段。例如,

      class AdvancedClauseSearchResultDTO { 
          private Date effectiveDate;
      
          private String status;
          .
          .
      
          public void getEffectiveDate() {
              return effectiveDate;
          }
      
          public void setEffectiveDate(Date aDate) {
                      Date now = new Date(System.currentTimeMillis());
                      if (now.before(effectiveDate)) {
                          this.status = "Pending";
                      } else if (now.after(terminationDate)) {
                          this.status = "Terminated";
                      } else {
                          this.status = "Active";
                      }
              this.effectiveDate = aDate;
          }
      }
      

      你明白了……

      【讨论】:

      • 我确实尝试过这个,但它并没有改变任何东西。
      【解决方案4】:

      最简单的解决方法是为列别名加上引号,例如:

      select first_name as "firstName" from employee
      

      【讨论】:

        猜你喜欢
        • 2018-06-14
        • 1970-01-01
        • 2014-11-09
        • 2018-06-26
        • 2014-03-06
        • 2013-04-11
        • 1970-01-01
        • 1970-01-01
        • 2012-04-18
        相关资源
        最近更新 更多