nHibernate linq提供程序扩展的表达式帮助

nHibernate linq提供程序扩展的表达式帮助,linq,nhibernate,hql,linq-expressions,nhlambdaextensions,Linq,Nhibernate,Hql,Linq Expressions,Nhlambdaextensions,我正在通过扩展BaseHQlGeneratorFormMethod为nHibernate开发一个自定义linq扩展。此处记录了该技术: 我已经成功地实现了各种类型的操作,但是我必须说——将一个简单的linq表达式转换为它的完整表达式树并不容易!我现在被卡在一个上面了 对于这个例子,我有三个实体员工,组和员工组。EmployeeGroup类在Employee和Group之间建立多对多关系。我必须专门创建中间类,因为还有其他属性需要跟踪,就像每个员工在每个组中拥有的特定权限一样。因此存在两种一对多

我正在通过扩展BaseHQlGeneratorFormMethod为nHibernate开发一个自定义linq扩展。此处记录了该技术:

我已经成功地实现了各种类型的操作,但是我必须说——将一个简单的linq表达式转换为它的完整表达式树并不容易!我现在被卡在一个上面了

对于这个例子,我有三个实体<代码>员工,
员工组
。EmployeeGroup类在Employee和Group之间建立多对多关系。我必须专门创建中间类,因为还有其他属性需要跟踪,就像每个员工在每个组中拥有的特定权限一样。因此存在两种一对多关系,而不是一种nHibernate多对多关系

现在,假设我要获取包含特定员工的所有组。我可以编写以下查询:

var groups = session.Query<Group>()
  .Where(g => g.EmployeeGroups.Any(eg => eg.Employee == employee));
这在查询本地组列表时有效,但不针对nHibernate会话。为此,我还必须创建一个linq扩展并注册它。就像在文章(上面链接)中一样,我创建了一个
GroupHasEmployeeGenerator
类,它扩展了
BaseHqlGeneratorForMethod
。我将其
.SupportedMethods
属性设置为引用我的HasEmployee扩展方法

我迷路的地方是对
BuildHql
的覆盖。要构建的表达式很快变得复杂。我想既然我正在替换
.Any
子句,那么最好从内置
AnyHqlGenerator
类的源代码开始。但这并没有考虑到源是原始元素的属性,也没有考虑到我没有一个lambda表达式来表示where子句。我需要手动构建这些部件

到目前为止,发布我的尝试是没有意义的,因为它们都离任何可行的东西都很远

有人能帮我将这个简单表达式转换成
BuildHql
方法覆盖的适当方法集吗?


如果有更好的文档,请告诉我。谢谢。

我知道这个问题已经问了一年了,但我今天在实现
BaseHqlGeneratorForMethod
时遇到了一个非常类似的问题

BuildHql
的输入包含传递给扩展方法的
System.Linq.Expressions.Expression
参数的集合。使用这些参数,可以构建表示扩展方法实现的表达式树。如果生成的表达式是NHibernate.Linq支持的,那么可以使用提供的
IHqlExpressionVisitor
将该表达式转换为Hql的子树

在您的示例中:

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);
}
公共重写HqlTreeNode BuildHql(MethodInfo方法、表达式targetObject、只读集合参数、HqlTreeBuilder treeBuilder、IHqlExpressionVisitor)
{
var AnyMethod=EnumerableHelper.GetMethod(“Any”,new[]{typeof(IEnumerable),typeof(Func)},new[]{typeof(EmployeeGroup)});
var EmployeeGroupsProperty=ReflectionHelper.GetProperty(g=>g.EmployeeGroups);
var EmployeeProperty=ReflectionHelper.GetProperty(eg=>eg.Employee);
var EmployeeGroupParameter=Expression.Parameter(typeof(EmployeeGroup));
var EmployeeGroupPredicate=Expression.Lambda(Expression.Equal(Expression.MakeMemberAccess(EmployeeGroupParameter,EmployeeProperty),参数[1]),EmployeeGroupParameter);
var CallExpression=Expression.Call(AnyMethod,Expression.MakeMemberAccess(参数[0],EmployeeGroupsProperty),EmployeeGroupPredicate);
回访访问者。访问(CallExpression);
}

我不能真正测试这个具体的例子,但在为我自己的扩展方法提供支持时,同样的方法对我有效。

我知道这个问题已经有一年了,但今天在实现
BaseHqlGeneratorForMethod
时,我遇到了一个非常类似的问题

BuildHql
的输入包含传递给扩展方法的
System.Linq.Expressions.Expression
参数的集合。使用这些参数,可以构建表示扩展方法实现的表达式树。如果生成的表达式是NHibernate.Linq支持的,那么可以使用提供的
IHqlExpressionVisitor
将该表达式转换为Hql的子树

在您的示例中:

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);
}
公共重写HqlTreeNode BuildHql(MethodInfo方法、表达式targetObject、只读集合参数、HqlTreeBuilder treeBuilder、IHqlExpressionVisitor)
{
var AnyMethod=EnumerableHelper.GetMethod(“Any”,new[]{typeof(IEnumerable),typeof(Func)},new[]{typeof(EmployeeGroup)});
var EmployeeGroupsProperty=ReflectionHelper.GetProperty(g=>g.EmployeeGroups);
var EmployeeProperty=ReflectionHelper.GetProperty(eg=>eg.Employee);
var EmployeeGroupParameter=Expression.Parameter(typeof(EmployeeGroup));
var EmployeeGroupPredicate=Expression.Lambda(Expression.Equal(Expression.MakeMemberAccess(EmployeeGroupParameter,EmployeeProperty),参数[1]),EmployeeGroupParameter);
var CallExpression=Expression.Call(AnyMethod,Expression.MakeMemberAccess(参数[0],EmployeeGroupsProperty),EmployeeGroupPredicate);
回访访问者。访问(CallExpression);
}

我无法真正测试这个特定的示例,但在为我自己的扩展方法提供支持时,同样的方法对我有效。

很有趣。我已经有一段时间没有做任何nhibernate了,所以我必须回去看看,这会解决问题的。不过,我认为这是一个公认的答案,因为它似乎在正确的轨道上。谢谢有趣。我还没做