Projections.sqlProjection 允许我们使用SQL嵌入到当前的hql中。
但是所使用的语句中只提供当前表的别名引用,对于其它关联表就没办法制定属性了。
应用场景:
criteria.createAlias("Test", "f",DetachedCriteria.LEFT_JOIN);
prolist.add(Projections.sqlProjection("(decode({f}.state,null,{alias}.state,{f}.state)) as state", new String[]{"state"},new Type[]{ Hibernate.STRING}));
预计输出:
(decode(f1_.state,null,this_.state,f1_.state)) as state
实际输出:
(decode({f}state,null,this_.state,{f}.state)) as state
别名为什么是 f1_ 而不是 f , 只是生成的别名规则。如果直接写上 f1_ 那就什么烦恼都没了。
求助了GG后,发现有人问,没人答。英文的倒是有几篇提到。果然烦恼什么的大家处理的都很彻底。
猜猜,(脑)补(脑)补,弄懂了大概的意思。
SQLProjection 确实只提供顶级的别名引用,但是可以通过自己的扩展实现其它别名引用.......。
好了,思路有了,就来实现吧。 点开 SQLProjection 的源码
public String toSqlString(Criteria criteria, int loc, CriteriaQuery criteriaQuery)
throws HibernateException
{
return StringHelper.replace(sql, "{alias}", criteriaQuery.getSQLAlias(criteria));
}
意思简单明了,实现起来也简单。
这是我写的一个扩展。
prolist.add(SQLProjectionExt.sqlProjection("(decode({f}.state,null,{alias}.state,{f}.state)) as state", new String[]{"state"}, Hibernate.STRING));
输出成理想的语句了。
public class SQLProjectionExt extends SQLProjection{
protected SQLProjectionExt(String sql, String[] columnAliases, Type[] types) {
super(sql, columnAliases, types);
// TODO Auto-generated constructor stub
}
public static SQLProjection sqlProjection(String sql, String[] columnAliases, Type... types)
{
return new SQLProjectionExt(sql, columnAliases, types);
}
@Override
public String toSqlString(Criteria criteria, int loc,
CriteriaQuery criteriaQuery) throws HibernateException {
// TODO Auto-generated method stub
String sql = super.toSqlString(criteria, loc, criteriaQuery);
Pattern p = Pattern.compile("\\{(\\w++)\\}");
Matcher m = p.matcher(sql);
StringBuffer sb = new StringBuffer();
while (m.find()) {
String s = m.group();
s = s.replace("{", "").replace("}", "")+".";
m.appendReplacement(sb, criteriaQuery.getSQLAlias(criteria, s));
}
m.appendTail(sb);
return sb.toString();
}
}