BUG简单描述:在Criteria联表查询中,Hibernate装组出无效的SQL。
版本:3.25GA,在最新版3.50rc2上BUG存在那个类中未发现有更改。
下面是简单的示例代码:
两个类:某类(FlexLink)和组织类(Organization),关系为多对一。
//创建查询器
DetachedCriteria c = DetachedCriteria.forClass(FlexLink.class, "_link");
//再创建一个子属性别名
c.createAlias("_link.organization", "organization");
//子属性的条件
c.add(Restrictions.eq("organization.orgName", "xxx"));
//只查部份属性
ProjectionList projectionList = Projections.projectionList();
projectionList.add(Projections.property("organization.orgName").as("organization.orgName"));
c.setProjection(projectionList);
//调用SPRING提供的DAO查询
flexLinkDAO.getHibernateTemplate().findByCriteria(c);
//生成的SQL:
select
organizati1_.ORGANIZATION_NAME as y0_
from
BIS_FLEX_LINK this_
inner join
SYS_ORGANIZATION organizati1_
on this_.ORGANIZATION_ID=organizati1_.ORGANIZATION_ID
where
y0_=?//问题就出在这里,这里可以用organizati1_.ORGANIZATION_NAME=?,但不能用y0_这个别名
上面的SQL在ORACLE和MYSQL上都是不能执行的,y0_这别名不能用作条件关键字,但是可以用在order by 名子中,如order by y0_。
那么是哪个类出错了?最直观看到的就是CriteriaQueryTranslator类的getColumnsUsingProjection方法:
/**
* Get the names of the columns constrained
* by this criterion.
* 此方法在criteria查中,把查询对象翻译成SQL时要用到,
* 用于取得JAVA属性名对应的SQL的字段名或SQL别名
* 在这里,getWhereCondition调用此方法组装where条件
*/
public String[] getColumnsUsingProjection(
Criteria subcriteria,
String propertyName) throws HibernateException {
//first look for a reference to a projection alias
final Projection projection = rootCriteria.getProjection();
//就是这一行有问题,就是这里返回了y0_这个别名,这里也不全错,上面说是order by y0_是可以的,
//Hibernate组装order by 句子的时也要调用此方法,
String[] projectionColumns = projection == null ?
null :
projection.getColumnAliases( propertyName, 0 );
if ( projectionColumns == null ) {
//it does not refer to an alias of a projection,
//look for a property
try {
return getColumns( propertyName, subcriteria );
}
catch ( HibernateException he ) {
//not found in inner query , try the outer query
if ( outerQueryTranslator != null ) {
return outerQueryTranslator.getColumnsUsingProjection( subcriteria, propertyName );
}
else {
throw he;
}
}
}
else {
//it refers to an alias of a projection
return projectionColumns;
}
}
改BUG方案:
方案一,改源码:就把那行有问题的直接改成String[] projectionColumns = null就可以,或者直接保留try catch块就可以了,不影响。
方案二,避免此问题:此问题的根本原因在于select句中为orgName这个字段建立了别名,所以在组装条件句时才取到别名,那如果select句中不查orgName这个字段就不会有这个问题。
如果有更好的解决方法,欢迎讨论。