私は NHibernate Linq プロバイダーを拡張しており、ビット パラメーターと戻り値の型の両方を持つユーザー定義を呼び出したいと考えています。
SQL ユーザー定義関数のシグネチャは次のとおりです。
FUNCTION f_DocumentsFreeTextSearch
(
@docId int,
@searchString varchar(8000),
@searchTitle bit
)
RETURNS bit
Linq の使用に使用される「偽の」拡張メソッドは次のとおりです。
public static class DialectExtensions
{
public static bool FreeText(this Document doc, string searchString, bool searchTitle)
{
return false;
}
}
これが私のLinqToHqlGeneratorsRegistryです
public sealed class ExtendedLinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
{
public ExtendedLinqToHqlGeneratorsRegistry()
{
DialectExtensions.FreeText(null, null, true)),
new FreeTextGenerator());
}
}
そして、ここに私のジェネレーターがあります:
public class FreeTextGenerator : BaseHqlGeneratorForMethod
{
public FreeTextGenerator()
{
SupportedMethods = new[]
{
ReflectionHelper.GetMethodDefinition(() => DialectExtensions.FreeText(null, null, true))
};
}
#region Overrides of BaseHqlGeneratorForMethod
public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
return treeBuilder.MethodCall("dbo.f_documentsfreetextsearch", arguments.Select(a => visitor.Visit(a).AsExpression()).ToArray());
}
#endregion
}
これは望ましい使用法です:
[TestMethod]
public void CanFreeText()
{
var query = SessionHolder.Current.Query<Document>();
var list = query.Where(d => d.FreeText("giorno", true)).ToList();
}
最初の問題: 上記のコードは InvalidCastException を引き起こします:
テスト メソッド App.Tests.NHMapping.CanFreeText が例外をスローしました: System.InvalidCastException: タイプ 'NHibernate.Hql.Ast.HqlMethodCall' のオブジェクトをタイプ 'NHibernate.Hql.Ast.HqlBooleanExpression' にキャストできません。
この方法で解決しました(エレガントではありませんが、機能します):
[TestMethod]
public void CanFreeText()
{
var query = SessionHolder.Current.Query<Document>();
var list = query.Where(d => d.FreeText("giorno", true) == true).ToList();
}
NHibernate はクエリを実行しますが、生成された SQL は間違っています。
テスト メソッド App.Tests.NHMapping.CanFreeText が例外をスローしました: NHibernate.Exceptions.GenericADOException: クエリを実行できませんでした [select [...] from dbo.DOCUMENTS document0_ where case when dbo.f_documentsfreetextsearch(document0_.IDDOCUMENT, @p0, @p1 =1) then 1 else 0 end=@p2 ] Name:p1 - Value:giorno Name:p2 - Value:True Name:p3 - Value:True [SQL: select [...] from dbo.DOCUMENTS document0_ where case when dbo.f_documentsfreetextsearch(document0_.IDDOCUMENT, @p0, @p1=1) then 1 else 0 end=@p2] ---> System.Data.SqlClient.SqlException: '=' 付近の構文が正しくありません。
生成された SQL の関数呼び出しには、3 番目のパラメーターとして @p1=1 があり、WHERE 句はインライン CASE ではなくインライン CASE であることに注意してください。
dbo.f_documentsfreetextsearch(document0_.IDDOCUMENT、@p0、@p1) = 1
私の期待通りに。
C# コードで bool パラメーターを変更し、戻り値の型を Int32 にすると、すべてがうまく機能します (ただし、まだあまりエレガントではありません)。
目的の構文を機能させる方法について何か考えはありますか?
前もって感謝します
クラウディオ
PS: たくさんのコードとエラーのテキストで申し訳ありません:P