您的位置:首页 > 数据库

简单修改Hibernate源码,增加使用原生SQL查询时动态addEntity和addScalar功能

2009-09-05 12:02 1111 查看
简单修改Hibernate源码,增加使用原生SQL查询时动态addEntity和addScalar功能
@for&ever 2009-9-5
相关文章,参考: http://blog.csdn.net/forandever/archive/2009/09/04/4520787.aspx
环境:
Hibernate3.3

在使用 Hibernate进行原生SQL查询的时候,必须要在createSQLQuery之后紧跟 addEntity或addScalar才可以,要想在离开初始的 createSQLQuery之后进行这个操作是不行的。
例如:
如下使用是可以的:
session.createSQLQuery(sql).addEntity("entityXXXX", XXXX.class).addScalar("strYYYY", Hibernate.STRING);
或者
session.createSQLQuery(sql).addEntity(XXXX.class).addScalar(Hibernate.STRING);

但如果在拆分开之后,就不能用了。例如:
Query q = session.createSQLQuery(sql);
q.addEntity(XXXX.class).addScalar(Hibernate.STRING); // XXXX 出错。 Eclipse下会提示错误。
这是Hibernate里按着实际的应用环境场景的设置,是没问题的。

但是,现在有这样的一个使用场景:
构建一个泛型的Dao,里面要能够根据多个参数动态的设置 addEntity 和 addScalar等。
如下的情形:
要实现一个如下的方法:
public List getListBySQL(String sql,String returnAliases[], Class returnClasses[]);

该方法的功能是,根据原生的sql查找到结果。sql 中设置的别名Aliases 可以动态的设置Entity
sql是传入的原生SQL,returnAliases[] 是别名的数组,returnClasses是要动态设置的Entity。
当sql不固定时,可以通过这个方法进行动态设置。

可能的实际例子:
如下的SQL语句:
select {bbbb.*}, {aaaa.*} from question {bbbb} left join answer {aaaa} on {aaaa}.id={bbbb}.ansId

实体类 Question 和 Answer需要动态设置。

如下的查询是可以的:
Query q = session.createSQLQuery(sql).addEntity(Question.class).addEntity(Answer.class);
但是如果每次的 sql语句参数都动态变化,并且要操作 addEntity 和 addScalar的数目也不确定的时候,就需要修改Hibernate的源码。

具体修改方法为:

1、修改接口 org.hibernate.Session,增加方法:

public Query createSQLQuery(String sql, String returnAliases[], Object returnObjectes[]);
这里的第三个参数 Object returnObjectes[] 类型是 Object,就是为了适应 Entity 和 Scalar的不同。

2、修改 org.hibernate.impl.AbstractSessionImpl,增加实现:

public Query createSQLQuery(String sql, String returnAliases[], Object returnObjectes[]){
errorIfClosed();
SQLQuery query = createSQLQuery(sql);
for(int i = 0; i < returnAliases.length; i ++){
if(returnAliases[i].startsWith("__")){
query.addScalar(returnAliases[i].substring(2), (Type) returnObjectes[i]);
}else{
query.addEntity(returnAliases[i], (Class)returnObjectes[i]);
}
}
return query;
}

当然,如果实现写在 SessionImpl 里面也可以。

一点小说明:
if(returnAliases[i].startsWith("__"))
这里是为了通过 Aliases 的值来判断是应该调用 addScalar 还是调用addEntity。
因此,要注意 returnAliases 的顺序和要设置的 returnObjectes 的顺序要对应才行。

接下来,就可以使用上面提到的 getListBySQL 方法,进行动态设置,参数如下:

String returnAliases[] = new String[]{ "bbbb", "aaaa"};
// Class returnClasses[] = new Class[] { Question.class, Answer.class}; // 使用下一行的 Object类型,兼容 Scalar 和 Entity
Object returnObjectes[] = new Object[] { Question.class, Answer.class};

修改一下 getListBySQL ,实现如下:
public List getListBySQL(String sql,String returnAliases[], Object returnObjectes[]){
Query q = session.createSQLQuery(sql , returnAliases, returnObjectes);
q.setParameter(...)
.........
}

经过查询后,就可以得到 Question 和 Answer 组合一起的 List。

这样就实现了根据传入的不同的SQL动态的设置查出的实体或者类型。

注:
Hibernate自身带有方法
public Query createSQLQuery(String sql, String returnAliases[], Class returnClasses[])
和方法
public Query createSQLQuery(String sql, String returnAlias, Class returnClass)
的实现。

但是它没有提供使用它们的接口。如果只是简单的使用以上的两个方法,也可以直接在接口的定义中加入以上两个方法。

但本文实现的方法,可以覆盖包含以上两个方法的功能。

@forandever 2009-9-5
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: