AliasToBeanResultTransformer和Hibernate SQLQuery

时间:2010-12-14 06:15:03

标签: java hibernate

我有一个相当复杂的查询(HQL或Criteria查询的嵌套级别太多),因此我将其编写为SQLQuery。我真的想使用AliasToBeanResultTransformer将我的结果转换为List,但是我遇到了一些问题。我已经将代码片段包含在我现在所拥有的代码片段之下。

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

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

查询字符串定义的开头片段,请注意'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;
        }
    }

4 个答案:

答案 0 :(得分:14)

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

各种数据库后端对列使用不区分大小写的命名,除非您正确地转义它们,因此它们最终会被检索为CLAUSEDETAILIDclausedetailid,即使您指定了列结果名称与正确的案例。

使用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所建议的那样。

答案 1 :(得分:4)

我今天对此做了一些更多的研究,最后注意到了我得到的潜在错误的良好堆栈跟踪,以及一个帮助我解决这个问题的hibernate论坛条目。

我得到的例外是: 引起:org.hibernate.PropertyNotFoundException:无法找到CLAUSEDETAILID的setter

似乎Hibernate正在使用我的骆驼案例别名&amp;将它们全部变为大写,因此无法在AdvancedClauseSearchResultDTO类中找到匹配的setter。

这是论坛条目,它指出了我正确的方向:

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

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

答案 2 :(得分:3)

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

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

在AdvancedClauseSearchResultDTO类中,修改setter方法以设置所需 你的领域。例如,

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

你明白了......

答案 3 :(得分:0)

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

select first_name as "firstName" from employee