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();
}
}