2

私が開発中のプロジェクトでは、Linq を使用していくつかの仕様を作成する必要があります。これで、値を検索する必要がある Dictionary ができました。NHibernate のデフォルトの Linq 実装は、ContainsValue 関数をサポートしていないため、独自の実装を作成することにしました。

そこで、次のように BaseHqlGeneratorForMethod から派生した ContainsValueGenerator という名前のクラスを作成しました。

public class ContainsValueGenerator : BaseHqlGeneratorForMethod
{
    public ContainsValueGenerator()
    {
        SupportedMethods = new[] { ReflectionHelper.GetMethodDefinition(() => new Dictionary<object, object>().ContainsValue(null)) };
    }

    public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
    {
        //Session.CreateQuery("from Message m where 'aDictionaryValue' in elements(m.Dictionary)"); 

        HqlTreeNode hqlTreeNode = treeBuilder.Elements(); // TODO include dictionary here? 
        return treeBuilder.In(visitor.Visit(arguments[0]).AsExpression(), hqlTreeNode);
        //return treeBuilder.In(visitor.Visit(arguments[0]).AsExpression(), treeBuilder.Indices(visitor.Visit(targetObject).AsExpression())); ContainsKey Method implementation 
    }
}

Nhibernate のソース コードを調べて、ContainsKey メソッドの実装を取り上げました。Hqlsyntax は、ContainsKey 構文と非常によく似ています。変更する必要がある唯一のこと (推測) は、treebuilder.Indices() の代わりに、treebuilder.Elements (コメントに表示) を使用する必要があることです。

それが私が立ち往生しているところです。ElementsExpression に独自の Dictionary を提供することはできません。Elements 式を利用する HqlTreeNode を作成するにはどうすればよいですか?

前もって感謝します、 ロブ・ヴァン・パメル

4

1 に答える 1

1

解決策は、HqlExpressionから継承する独自のHqlElementsクラスを作成することです。実際、これはHqlIndicesクラスの単なるコピーです。

public class HqlElements : HqlExpression
{
    public HqlElements(IASTFactory factory, HqlExpression dictionary)
        : base(HqlSqlWalker.ELEMENTS, "elements", factory, dictionary)
    {
    }
}

トリッキーな部分は、これをプロパティとしてHqlTreeBuilderクラスに追加することです。したがって、拡張メソッドを使用できます。これには、リフレクションを使用してHqlTreeBuilderのファクトリを取得するための醜いコードが1つ含まれています。

public static class HqlTreeBuilderExtensions
{
    public static HqlElements Elements(this HqlTreeBuilder treeBuilder, HqlExpression dictionary)
    {
        var factory = (IASTFactory) treeBuilder.GetType().GetField("_factory", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(treeBuilder);

        return new HqlElements(factory, dictionary);
    }
}

これで、ジェネレータを次のように変更できます。

public class ContainsValueGenerator : BaseHqlGeneratorForMethod
{
    public ContainsValueGenerator()
    {
        SupportedMethods = new[] { ReflectionHelper.GetMethodDefinition(() => new Dictionary<object, object>().ContainsValue(null)) };
    }

    public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
    {
        return treeBuilder.In(visitor.Visit(arguments[0]).AsExpression(), treeBuilder.Elements(visitor.Visit(targetObject).AsExpression()));
    }
}

最善の解決策は、このコードがNHibernate自体に組み込まれることです。そのためのパッチをGitHubに追加するかもしれません。

于 2012-05-08T07:25:24.447 に答える