1

BaseHqlGeneratorForMethod を拡張することにより、nHibernate のカスタム linq 拡張に取り組んでいます。テクニックはここに文書化されています: http://fabiomaulo.blogspot.com/2010/07/nhibernate-linq-provider-extension.html

さまざまな種類の操作でこれらを実装することに成功しましたが、単純な linq 式を完全な式ツリーに変換するのは簡単ではありません。私は今、1つにこだわっています。

この例では、3 つのエンティティがあります。 EmployeeGroup、およびEmployeeGroup。EmployeeGroup クラスは、Employee と Group の間に多対多の関係を設定します。各従業員が各グループで持つ特定のアクセス許可など、追跡する追加のプロパティがあるため、特に中間クラスを作成する必要があります。したがって、nHibernate の多対多の関係ではなく、2 つの 1 対多の関係があります。

ここで、特定の従業員を含むすべてのグループを取得したいとします。このクエリを書くことができます:

var groups = session.Query<Group>()
  .Where(g => g.EmployeeGroups.Any(eg => eg.Employee == employee));

これは問題なく機能しますが、入力するのは大変です。私はむしろこれを行うことができます:

var groups = session.Query<Group>().Where(g => g.HasEmployee(employee));

次のような拡張メソッドを作成することから始めます。

public static bool HasEmployee(this Group group, Employee employee)
{
  return group.EmployeeGroups.Any(eg => eg.Employee == employee);
}

これは、グループのローカル リストをクエリするときに機能しますが、nHibernate セッションに対しては機能しません。そのためには、linq 拡張機能も作成して登録する必要があります。記事 (上記のリンク) と同じように、GroupHasEmployeeGeneratorを拡張するクラスを作成しますBaseHqlGeneratorForMethod.SupportedMethodsHasEmployee 拡張メソッドを参照するようにそのプロパティを設定しました。

私が迷子になるのは、へのオーバーライドBuildHqlです。構築する式はすぐに複雑になります。私は.Any句を置き換えているので、組み込みクラスのソースから始めるのが良いでしょうAnyHqlGenerator。ただし、ソースが元の要素のプロパティであることは考慮されていません。また、where 句を表すラムダ式がないことも考慮されていません。これらのパーツを手動で作成する必要があります。

これまでのところ、私の試みを投稿しても意味がありません.

この単純な式をメソッドのオーバーライドに適した一連のメソッドに変換するのを誰か手伝ってくれませんBuildHqlか?

これに関するより良いドキュメントがあれば、私に知らせてください。ありがとう。

4

1 に答える 1

1

この質問は1年前のものであることは知っていますが、BaseHqlGeneratorForMethod今日の実装時に非常によく似た問題に遭遇しました.

への入力には、拡張メソッドに渡される引数BuildHqlのコレクションが含まれます。System.Linq.Expressions.Expressionこれらの引数を使用して、拡張メソッドの実装を表す式ツリーを構築できます。結果の式が NHibernate.Linq でサポートされているものである場合、提供された を使用してその式を Hql のサブツリーに変換できますIHqlExpressionVisitor

あなたの例では:

public static bool HasEmployee(this Group group, Employee employee)
{
  return group.EmployeeGroups.Any(eg => eg.Employee == employee);
}

これは次のようになります。

public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
    var AnyMethod = EnumerableHelper.GetMethod("Any", new[] {typeof(IEnumerable<EmployeeGroup>), typeof(Func<EmployeeGroup, bool>)}, new[] {typeof(EmployeeGroup)});
    var EmployeeGroupsProperty = ReflectionHelper.GetProperty<Group>(g => g.EmployeeGroups);
    var EmployeeProperty = ReflectionHelper.GetProperty<EmployeeGroup>(eg => eg.Employee);

    var EmployeeGroupParameter = Expression.Parameter(typeof(EmployeeGroup));
    var EmployeeGroupPredicate = Expression.Lambda(Expression.Equal(Expression.MakeMemberAccess(EmployeeGroupParameter, EmployeeProperty), arguments[1]), EmployeeGroupParameter);

    var CallExpression = Expression.Call(AnyMethod, Expression.MakeMemberAccess(arguments[0], EmployeeGroupsProperty), EmployeeGroupPredicate);

    return visitor.Visit(CallExpression);
}

この特定の例を実際にテストすることはできませんが、独自の拡張メソッドのサポートを提供するときに同じアプローチが機能しました。

于 2012-07-27T20:39:38.607 に答える