FREETEXT搜索' column_list'使用hibernate CriteriaBuilder

时间:2017-09-13 00:46:10

标签: sql-server hibernate jpa

是否可以使用jpa CriteriaBuilder在 column_list 上调用Microsoft SQL Server的FREETEXT函数?

可以在单个列或列列表上本机调用SQL Server的FREETEXT函数: https://docs.microsoft.com/en-us/sql/t-sql/queries/freetext-transact-sql

我发现这个后可以在一个列上调用FREETEXT: https://stackoverflow.com/a/18534291/6659983

当我尝试在多个列上调用FREETEXT时,在调用FREETEXT时,我无法找到一种方法来让hibernate在 column_list 周围添加括号。

我覆盖ParamaterizedFunctionExpression.renderArguments()并最终设法获得生成的HQL(或某种中间类型的QL),如下所示:

select 
    generatedAlias0 
from 
    package.model.entity as generatedAlias0 
    inner join generatedAlias0.categories as generatedAlias1 
    inner join generatedAlias1.unspsc as generatedAlias2 
    inner join generatedAlias0.buyer as generatedAlias3 
    inner join generatedAlias0.otherEntity as generatedAlias4 
where 
    ( function('FREETEXT',  ( generatedAlias0.title, generatedAlias0.description, generatedAlias0.code, generatedAlias3.name, generatedAlias3.legalName, generatedAlias2.title ) , :param0) ) and ( generatedAlias0.state=:param1 ) 
    and ( generatedAlias0.state<>:param2 ) 
    and ( generatedAlias0.state<>:param3 ) 
    and ( generatedAlias0.state<>:param4 ) 
order by 
    generatedAlias0.closingDate asc]

我收到了这个错误:

    java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected AST node: function (FREETEXT) near line 1, column 319 [select generatedAlias0 from package.model.Entity as generatedAlias0 inner join generatedAlias0.categories as generatedAlias1 inner join generatedAlias1.unspsc as generatedAlias2 inner join generatedAlias0.buyer as generatedAlias3 inner join generatedAlias0.entityBoxes as generatedAlias4 where ( function('FREETEXT', ( generatedAlias0.title, generatedAlias0.description, generatedAlias0.code, generatedAlias3.name, generatedAlias3.legalName, generatedAlias2.title ) , :param0) ) and ( generatedAlias0.state=:param1 ) and ( generatedAlias0.state<>:param2 ) and ( generatedAlias0.state<>:param3 ) and ( generatedAlias0.state<>:param4 ) order by generatedAlias0.closingDate asc]
        at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:131)
        at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:155)
        at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:162)
        at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:663)
        at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:3318)
        at org.hibernate.query.criteria.internal.CriteriaQueryImpl$1.buildCompiledQuery(CriteriaQueryImpl.java:318)
        at org.hibernate.query.criteria.internal.compile.CriteriaCompiler.compile(CriteriaCompiler.java:127)
        at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:3611)
        at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:203)
        at package.entity.dao.EntityDaoImpl.search(EntityDaoImpl.java:241)

这是我努力扩展ParameterizedFunctionExpression:

/**
     * Overrides the {@link ParameterizedFunctionExpression.renderArguments()} function
     * so that the FREETEXT search can be created properly.
     */
    private class FreeTextExpression extends ParameterizedFunctionExpression<Boolean> implements Predicate {

        /**
         * Eclipse Generated UID.
         */
        private static final long serialVersionUID = -1219262363097942038L;

        private List<Expression<?>> argumentExpressions;

        /**
         * Constructs a FreeTextExpression
         * @param criteriaBuilder
         * @param returnType
         * @param functionName
         * @param argumentExpressions
         */
        public FreeTextExpression(
                CriteriaBuilderImpl criteriaBuilder,
                String functionName,
                List<Expression<?>> argumentExpressions) {
            super( criteriaBuilder, (Class<Boolean>) Boolean.class , functionName , argumentExpressions);
            this.argumentExpressions = argumentExpressions;
        }

        /**
         * Places all arguments except the first within brackets in order to define a MSSQL 'column_list'.
         */
        @Override
        protected void renderArguments(StringBuilder buffer, RenderingContext renderingContext) {
            String sep = "";
            buffer.append(" ( ");
            for (int i = 0; i < argumentExpressions.size() - 1 ; i ++) {
                buffer.append( sep ).append( ( (Renderable) argumentExpressions.get(i) ).render( renderingContext ) );
                sep = ", ";
            }
            buffer.append(" ) ");
            buffer.append( sep ).append( ( (Renderable) argumentExpressions.get(argumentExpressions.size() - 1) ).render( renderingContext ) );
        }

        @Override
        public BooleanOperator getOperator() {
            return Predicate.BooleanOperator.AND;
        }

        @Override
        public boolean isNegated() {
            return false;
        }

        @Override
        public List<Expression<Boolean>> getExpressions() {
            return Arrays.asList(this);
        }

        @Override
        public Predicate not() {
            return null;
        }
    }

以下是我如何使用它:

    List<Expression<?>> arguments = Arrays.asList(
                    entity.<String>get(Entity_.title),
                    entity.<String>get(Entity_.description),
                    entity.<String>get(Entity_.code),
                    buyer.<String>get(Business_.name),
                    buyer.<String>get(Business_.legalName),
                    unspsc.<String>get(Unspsc_.title),
                    (Expression<String>) keywords
            );

            Expression<Boolean> freeTextExpression = new FreeTextExpression(
                    (CriteriaBuilderImpl) builder, "FREETEXT", arguments);
            criteria.add((Predicate) freeTextExpression);

2 个答案:

答案 0 :(得分:0)

哎呀,我意识到我需要注册这样的函数,但对于FREETEXT:

registerFunction("CONTAINS", new SQLFunctionTemplate(StandardBasicTypes.BOOLEAN, "CONTAINS(?1, ?2) AND 1"));

Hibernate + MSSQL + Fulltext Search via Contains SQLFunctionTemplate

一旦我完成了它就会发布代码,除非有人能打败我!

答案 1 :(得分:-1)

请试试这个:

select 
    generatedAlias0 
from 
    package.model.entity as generatedAlias0 
    inner join generatedAlias0.categories as generatedAlias1 
    inner join generatedAlias1.unspsc as generatedAlias2 
    inner join generatedAlias0.buyer as generatedAlias3 
    inner join generatedAlias0.otherEntity as generatedAlias4 
where 
    FREETEXT( generatedAlias0,@param0) ) and ( generatedAlias0,@param1 ) 
    and ( generatedAlias0.state<>:param2 ) 
    and ( generatedAlias0.state<>:param3 ) 
    and ( generatedAlias0.state<>:param4 ) 
order by 
    generatedAlias0.closingDate asc]