在这,多次提到使用构造型查询,主要是我不想取出结果后再转型,这样,自己也实在太累了,因此,非常希望让openJPA一下就将结果做好,毕竟感觉上性能也要好过使用简单查询方式。
I.openJPA的构造型查询
openJPA在构造型查询方面好过其它几家,它支持三种方式:
1.通过反射注入,通过setXXX(字段名)注入到目标类(dto对象)的字段中
2.通过put方法,目标类(dto对象)需实现public void put(Object field, Object value)接口方法,然后openJPA的结果包装器调用此接口,将数据写到对象中
3.通过构造方法,目标类(dto对象)提供所需的构造函数,然后openJPA的结果包装器通过该构造函数实例化.
第1种方式最好,第3种方式最差,特别是对于查询结果比较多,做构造函数简直就是不可能的事
用第1种方式,虽然最好,但在openJPA0.9.6,0.9.7及1.0.0中对于使用JPQL这种方式均受到限制,缺省情况下openJPA提供的字段名是jpqlalias1,..,而你的DTO对象不可能定义为jpqlalias1,,这样的字段,这样就脱离了业务场景,其它开好人员根本不会用.因此,如果构造型查询的JPQL如果支持别名,这就太好了.我做了以下修改:
II.修改方案
1.修改[openjpa-kernel\src\main\jjtree\org\apache\openjpa\kernel\jpql\JPQL.jjt]
void constructor_parameter() #CONSTRUCTORPARAM : { }
{
(path() | aggregate_select_expression() | string_literal() | numeric_literal()) [LOOKAHEAD(1)<AS>] [LOOKAHEAD(identification_variable())identification_variable()]
}
2.修改org.apache.openjpa.kernel.jpql.JPQLExpressionBuilder.java
private Expression assignProjections(JPQLNode parametersNode,
QueryExpressions exps) {
int count = parametersNode.getChildCount();
exps.projections = new Value[count];
exps.projectionClauses = new String[count];
exps.projectionAliases = new String[count];
Expression exp = null;
JPQLNode parentNode = null;
JPQLNode itemNode = null;
JPQLNode aliasNode = null;
String alias = null;
for (int i = 0; i < count; i++) {
parentNode = parametersNode.getChild(i);
itemNode = firstChild(parentNode);
aliasNode = parentNode.children.length == 2 ? right(parentNode) : null;
alias = aliasNode == null ? lastChild(itemNode).text : aliasNode.text;
exps.projections[i] = getValue(itemNode);
exps.projectionAliases[i] = alias == null ? nextAlias() : alias;
}
return exp;
}
3.用mvn重新编译打包,一切ok.
III.使用示例
场景:
/** *//**
* A实体的一个DTO对象
*/
public class AData {
private String id; //标识
private String type; //类型
private String name; //名称
private int cnt; //子的总数
}
@Entity
@Table(..)
private class A {
@ID
@GeneratedValue(generator = "uuid-hex")
@Column(..)
private String id;
@Column(..)
private String aName;
@Column(..)
private String parentID;
@OneToMany
@Join..
private List<A> children;
}
JPQL语法如下:
select distinct new com.wile.test.AData(a.id, a.aName name, size(a.children) as cnt,'00' type) from A a where a.id=?1
虽然,我写的JPQL不太符合规范,但实在是太符合我的要求了.