【发布时间】:2015-04-04 20:50:24
【问题描述】:
我真的想在休眠查询中使用嵌套属性作为命名参数。 所以我可以更优雅地维护我的 param bean。
例如,我想写我的 HQL:
"......
where
employee.age >= :age.min
and
employee.age <= :age.max
and
employee.name = :name"
并将所有参数放入一个 paramBean, 在这个 paramBean 中,有一个嵌套的 bean(名为“age”), 并且嵌套的bean有2个属性:min和max。
但问题是:
- HQL 语法不支持作为命名参数的嵌套属性: Hibernate 会抛出异常,因为它不允许使用 “。”在参数名称中。
-
在 org.hibernate.internal.AbstractQueryImpl.setProperties(Object) 方法,实现代码为:
Getter getter = ReflectHelper.getGetter( clazz, namedParam ); Class retType = getter.getReturnType(); final Object object = getter.get( bean );
它在param bean上使用getter方法,所以它无法检索嵌套属性。
我必须在 param bean 中创建很多委托方法来访问嵌套属性:
public int getAgeMin() {
return this.age.getMin();
}
public int getAgeMax() {
return this.age.getMax();
}
并像这样编写 HQL:
"......
where
employee.age >= :ageMin
and
employee.age <= :ageMax
and
employee.name = :name"
这个问题困扰了我多年。
我终于找到了修复它的方法。
解决办法如下:
- 对于问题 (1):在 HQL 中:使用“_”作为“.”的转义字符
HQL 喜欢:
"......
where
employee.age >= :age_min
and
employee.age <= :age_max
and
employee.name = :name"
- 针对问题(2):编写一些辅助方法,设置所有参数值 为 HQL。
辅助方法的代码是:
private void setParameters(final Query query, final Object paramBean) {
for (String namedParam : query.getNamedParameters()) {
try {
// !!! Fix problem (1) !!!
// unescape the param name into nested property name
String nestedPropName = StringUtils.replace(namedParam, "_",
".");
// !!! Fix problem (2) !!!
// retrieve the nested property, using Apache Commons BeanUtils
// see: http://commons.apache.org/proper/commons-beanutils/
Object paramValue = PropertyUtils.getNestedProperty(paramBean,
nestedPropName);
Class<?> paramType = null;
if (paramValue != null) {
paramType = paramValue.getClass();
}
if ((paramType != null)
&& Collection.class.isAssignableFrom(paramType)) {
query.setParameterList(namedParam,
(Collection<?>) paramValue);
} else if ((paramType != null) && paramType.isArray()) {
query.setParameterList(namedParam, (Object[]) paramValue);
} else {
Type type = this.guessType(paramType);
query.setParameter(namedParam, paramValue, type);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private Type guessType(final Class<?> clazz) throws HibernateException {
SessionFactoryImplementor sessionFactoryImplementor = (SessionFactoryImplementor) this.sessionFactory;
String typeName = clazz.getName();
Type type = sessionFactoryImplementor.getTypeResolver().heuristicType(
typeName);
boolean serializable = type != null && type instanceof SerializableType;
if (type == null || serializable) {
try {
sessionFactoryImplementor.getEntityPersister(clazz.getName());
} catch (MappingException me) {
if (serializable) {
return type;
} else {
throw new HibernateException(
"Could not determine a type for class: " + typeName);
}
}
return this.getSession().getTypeHelper().entity(clazz);
} else {
return type;
}
}
重点是[!!!修复问题 (1) !!!] 和 [!!!修复问题 (2) !!!],
所有其他代码都简单地从 org.hibernate.internal.AbstractQueryImpl 复制
【问题讨论】:
标签: java sql hibernate parameters param