2011-08-31 95 views
1

我正在通過擴展BaseHqlGeneratorForMethod來爲nHibernate定製linq擴展。這項技術被記錄在這裏: http://fabiomaulo.blogspot.com/2010/07/nhibernate-linq-provider-extension.html有關nHibernate linq提供程序擴展表達式的幫助

我已經受夠了實施這些對各種操作的成功,但我必須說 - 一個簡單的LINQ表達式轉換爲充分表達式樹是不容易!我現在被卡住了。

對於這個例子,我有三個實體。 EmployeeGroupEmployeeGroup。 EmployeeGroup類在Employee和Group之間建立了多對多的關係。我必須特別創建中間類,因爲有其他屬性可以跟蹤每個員工在每個組中具有的特定權限。所以有兩個一對多的關係,而不是nHibernate的多對多關係。

現在說我想獲得包含特定員工的所有組。我可以寫這個查詢:

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。我將其.SupportedMethods屬性設置爲引用我的HasEmployee擴展方法。

我迷路的地方是覆蓋到BuildHql。構建的表達式變得非常複雜。我想,因爲我正在取代.Any條款 - 一個很好的起點是內置AnyHqlGenerator類的來源。但是這並沒有考慮到源是原始元素的屬性,也沒有考慮到我沒有用lambda表達式來表示where子句。我需要手動構建這些部件。

有在張貼我嘗試到目前爲止沒有意義的,因爲他們都來自任何會工作得非常遠。

有人請幫助我將這個簡單的表達式轉換爲BuildHql方法重寫的適當方法集合嗎?

如果有什麼更好的文檔在那裏此,請讓我知道。謝謝。

回答

1

我知道這個問題是一歲,但今天實施時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); 
} 

我真的不能測試這個具體的例子,但提供支持時同樣的方法爲我工作爲我自己的擴展方法。

+0

有趣。我在一段時間內沒有做過任何修改,所以我必須回去看看它能解決問題。儘管如此,我將它標記爲接受的答案,因爲它似乎是正確的。謝謝! –