Verwenden von CONTAINS von HQL / Criteria API

Ich benutze NHibernate 2.1.2.4000GA. Ich versuche, SQL server's CONTAINS function aus HQL und die Kriterien APIs zu verwenden. Das funktioniert gut in HQL:

 CONTAINS(:value) 

Allerdings muss ich den Tisch in Frage stellen. Das funktioniert gut:

 CONTAINS(table.Column, :value) 

Allerdings muss ich über alle indizierten Spalten in meiner Tabelle suchen. Ich habe das versucht:

 CONTAINS(table.*, :value) 

Aber ich bekomme:

 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) 

So scheinen die HQL-Parser-Drosseln auf dem Sternchen zu sein. Ich dachte daran, dies zu tun:

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

Nicht nur ist dies ineffizient, es kann auch errorshafte Ergebnisse liefern, abhängig vom Volltext Prädikat in :value .

Ich habe versucht, meinen Dialekt nach diesen statementen anzupassen, aber das hilft nicht, weil du immer noch mit demselben Problem verbleibst: Spezifizierung der table.* verursacht den HQL-Parser umherfallen.

Ich dachte an die Angabe von Abfragesubstitutionen:

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

Und dann einfach:

 TABLECONTAINS(:value) 

Aber das funktioniert nicht. Ich bin mir nicht sicher, warum – durch den resultierenden Fehler beurteilt wird, die Substitution einfach nicht stattfindet, weil "TABLECONTAINS" noch in der Abfrage vorhanden ist. Außerdem würde das nicht für alle Fälle funktionieren, denn ich müsste den Alias ​​des Tisches kennen und ihn dynamisch replace.

Deshalb habe ich einen intercept-basierten Ansatz gerollt:

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

Das funktioniert und ich werde jetzt heute Nacht schlafen können, aber ich fühle einen plötzlichen Wunsch, Londons bevorstehende päpstliche procession zu besuchen und ein Geständnis zu schreien.

Kann jemand einen besseren path finden, dies zu erreichen?

Warum nicht eine ISQLQuery verwenden?

Sie können immer noch Entitäten abrufen, siehe http://nhibernate.info/doc/nh/en/index.html#querysql-creating

Ich würde denken, dass ein benutzerdefinierter Dialekt der richtige path wäre, dies zu bewältigen. Sie finden eine Anleitung in diesem Artikel . Ich habe diesen Ansatz verwendet, um SQL server-spezifische functionen wie ISNULL für den deployment in unseren Projekten zu registrieren.