0

介绍

我有一个奇怪的任务 - 在 Hibernate Criteria API(即数据库独立风格)上编写类似于

select * from branch b where '2/5/3/' like b.hier_path + '%' 

连接运算符在哪里+。连接运算符是 MS SQL 中依赖于数据库的“+”,“||” 在甲骨文等

我必须使用 Criteria API(并且无法切换到 HQL)。

问题 #1 - 类似运算符

不幸的是,Hibernate 只允许编写基于 Java 对象属性的 Criteria:

pCriteria.createCriteria(Branch.class).add(Restrictions.like("hierarchyPath", "2/5/3/%"));

相当于

select * from branch where 'hier_path like 2/5/3/%'

我不知道如何交换 like 运算符的操作数。

问题 #2 - 独立于数据库的连接

SQL 代码必须适用于 Oracle、MS SQL Server、DB2、Postgres、Sybase、MySQL、HSQLDB、Firebird(和其他一些新的关系数据库)。

我现在得到的是基于 SQL 的 hack:

Restrictions.sqlRestriction("? like concat({alias}.hier_path,'%')", "2/5/3/", Hibernate.STRING)

不幸的是,concat上述数据库(Postgres 和 Firebird 除外)中大多数都存在依赖于数据库的功能。该方法是一种解决方法,不能用作常量解决方案(我将尝试将自定义函数添加concat到没有它的数据库)。

结论

有人可以提出改进我的 hack(独立于数据库的 SQL)或更正原始 CriteriaAPI 的建议吗?

更新 28.09.12

concat函数出现在 Postgres 9.1

4

2 回答 2

1

您可以编写自己的 Criterion 实现,它会生成一个类似于您在问题中的 SQL 子句,除了它将使用与条件查询关联的方言来获取适当的 concat 函数并将连接委托给这个依赖于数据库的连接函数。

于 2012-09-28T12:02:02.003 回答
0

谢谢@JB 尼泽。受他的想法启发的代码:

private class InverseLikeExpression extends SimpleExpression{
    private static final String CONST_HQL_FUNCTION_NAME_CONCAT = "concat";
    private static final String CONST_LIKE = " like ";
    private static final String CONST_LIKE_SUFFIX = "'%'";

    private final String propertyName;

    protected InverseLikeExpression(String pPropertyName, Object pValue) {
        super(pPropertyName, pValue, CONST_LIKE);
        propertyName = pPropertyName;
    }

    @Override
    public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
        String[] columns = criteriaQuery.getColumnsUsingProjection(criteria, propertyName);
        Dialect dialect = criteriaQuery.getFactory().getDialect();
        SQLFunction concatFunction = (SQLFunction) dialect.getFunctions().get(CONST_HQL_FUNCTION_NAME_CONCAT);

        StringBuffer fragment = new StringBuffer();
        if (columns.length>1) fragment.append('(');
        for ( int i=0; i<columns.length; i++ ) {
            String fieldName = concatFunction.render(Arrays.asList(new Object[] {columns[i], CONST_LIKE_SUFFIX}), criteriaQuery.getFactory());
            fragment.append("?").append( getOp() ).append(fieldName);
            if ( i<columns.length-1 ) fragment.append(" and ");
        }
        if (columns.length>1) fragment.append(')');
        return fragment.toString();
    }       
}
于 2012-09-28T16:18:33.577 回答