Использование CONTAINS из HQL / Criteria API - PullRequest
1 голос
/ 16 сентября 2010

Я использую NHibernate 2.1.2.4000GA. Я пытаюсь использовать функцию SQL Server CONTAINS из HQL и API критериев. Это отлично работает в HQL:

CONTAINS(:value)

Тем не менее, мне нужно квалифицировать данную таблицу. Это отлично работает:

CONTAINS(table.Column, :value)

Однако мне нужно выполнить поиск по всем проиндексированным столбцам в моей таблице. Я попробовал это:

CONTAINS(table.*, :value)

Но я получаю:

NHibernate.Hql.Ast.ANTLR.QuerySyntaxException : Exception of type 'Antlr.Runtime.MissingTokenException' was thrown. near line ... [select table.Id from Entities.Table table where CONTAINS(table.*,:p0) order by table.Id asc]
    at NHibernate.Hql.Ast.ANTLR.ErrorCounter.ThrowQueryException()
    at NHibernate.Hql.Ast.ANTLR.HqlParseEngine.Parse()
    at NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.Parse(Boolean isFilter)
    at NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.DoCompile(IDictionary`2 replacements, Boolean shallow, String collectionRole)
    at NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.Compile(IDictionary`2 replacements, Boolean shallow)
    at NHibernate.Engine.Query.HQLQueryPlan..ctor(String hql, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
    at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(String queryString, Boolean shallow, IDictionary`2 enabledFilters)
    at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(String query, Boolean shallow)
    at NHibernate.Impl.AbstractSessionImpl.CreateQuery(String queryString)

Так что, похоже, HQL-парсер захлестнет звездочку. Я думал сделать это:

CONTAINS(table.Column1, :value) or CONTAINS(table.Column2, :value)

Мало того, что это неэффективно, оно также может давать неправильные результаты в зависимости от предиката полного текста в :value.

Я попытался настроить свой диалект согласно этим инструкциям , но это не помогло, потому что у вас все еще осталась та же проблема: указание table.* приводит к падению HQL-анализатора. *

Я думал об указании подстановок запросов:

<property name="query.substitutions">TABLECONTAINS(=CONTAINS(table.*,</property>

А потом просто делаем:

TABLECONTAINS(:value)

Но это не работает. Я не уверен, почему - судя по возникшей ошибке, подстановка просто не происходит, потому что в запросе по-прежнему присутствует «TABLECONTAINS». Кроме того, это не будет работать для всех случаев, потому что мне нужно знать псевдоним таблицы и динамически подставлять его в.

Поэтому я применил подход, основанный на перехвате:

using System;
using NHibernate;
using NHibernate.SqlCommand;

public class ContainsInterceptor : EmptyInterceptor
{
    public override SqlString OnPrepareStatement(SqlString sql)
    {
        var indexOfTableContains = sql.IndexOfCaseInsensitive("TABLECONTAINS(");

        if (indexOfTableContains != -1)
        {
            var sqlPart = sql.ToString();
            var aliasIndex = sqlPart.LastIndexOf("Table ", indexOfTableContains, StringComparison.Ordinal);

            if (aliasIndex == -1)
            {
                return sql;
            }

            aliasIndex += "Table ".Length;
            var alias = sqlPart.Substring(aliasIndex, sqlPart.IndexOf(" ", aliasIndex, StringComparison.Ordinal) - aliasIndex);
            sql = sql.Replace("TABLECONTAINS(", "CONTAINS(" + alias + ".*,");
        }

        return base.OnPrepareStatement(sql);
    }
}

Это работает, и теперь я смогу спать сегодня вечером, но я чувствую внезапное желание посетить предстоящее папское шествие Лондона и выкрикивать признание.

Кто-нибудь может предложить лучший способ добиться этого?

Ответы [ 2 ]

0 голосов
/ 17 сентября 2010

Почему бы не использовать вместо этого ISQLQuery?

Вы все еще можете получить объекты, см. http://nhibernate.info/doc/nh/en/index.html#querysql-creating

0 голосов
/ 16 сентября 2010

Я думаю, что собственный диалект будет подходящим способом справиться с этим. Вы можете найти некоторые рекомендации в этой статье . Я использовал этот подход для регистрации специфичных для SQL Server функций, таких как ISNULL, для использования в наших проектах.

...