2010-11-12 57 views
3

當前我們正在使用一個通用資源庫,用於公開IQueryable(使用NH3 linq支持)的所有實體,然後由我們的服務層用於構造特定查詢。NHibernate Linq Eager使用通用資源庫加載

我現在需要急切加載關聯。有什麼辦法可以公開一個IQueryable並傳入可選的獲取表達式?我看到的問題是Fetch必須在表達式中最後(根據http://mikehadlow.blogspot.com/2010/08/nhibernate-linq-eager-fetching.html)。

我很好奇其他人如何實現這一目標。

我的確考慮過可能將Linq規範傳遞給存儲庫,以便在調用Fetch之前對它們進行評估。然而,我仍然需要一些傳遞Fetch表達式的方法。

感謝 本

回答

3

我用我的FindOneFindAll庫的重載調用來實現this..something,如:

Function FindOne(ByVal spec As ILinqSpecification(Of T)) As T 
Function FindOne(ByVal spec As ILinqSpecification(Of T), ByVal strategy As IFetchingStrategy(Of T)) As T 
Function FindAll(ByVal spec As ILinqSpecification(Of T)) As IQueryable(Of T) 
Function FindAll(ByVal spec As ILinqSpecification(Of T), ByVal strategy As IFetchingStrategy(Of T)) As IQueryable(Of T) 

等。

也許不是最乾淨的方法,但它完成這項工作。我不確定這是否仍然是主幹linq提供程序的問題,但我也可以根據我的提取策略是否包含一個或多個選項來決定是否將不同的結果轉換器應用於FindAll方案中的結果採集。

我的規範和抓取策略實現基於ncommon項目中的可用規範。

僅供參考,我完全通用的「只讀」資料庫界面如下:

Public Interface IReadOnlyRepositoryWithTypedId(Of T As IEntityWithTypedId(Of IdT), IdT) 

    Function LoadById(ByVal id As IdT) As T 
    Function GetById(ByVal id As IdT) As T 
    Function FindOne(ByVal spec As ILinqSpecification(Of T)) As T 
    Function FindOne(ByVal spec As ILinqSpecification(Of T), ByVal strategy As IFetchingStrategy(Of T)) As T 
    Function GetCount() As Integer 
    Function GetCount(ByVal spec As ILinqSpecification(Of T)) As Integer 
    Function HasAny(ByVal spec As ILinqSpecification(Of T)) As Boolean 
    Function FindAll(ByVal spec As ILinqSpecification(Of T)) As IQueryable(Of T) 
    Function FindAll(ByVal spec As ILinqSpecification(Of T), ByVal strategy As IFetchingStrategy(Of T)) As IQueryable(Of T) 
    Function FindAll() As IQueryable(Of T) 
    Function FindAll(ByVal strategy As IFetchingStrategy(Of T)) As IQueryable(Of T) 

End Interface 
+0

是否使用LinqSpecs?你可能會張貼這些方法的完整簽名嗎? – 2010-11-12 14:10:41

+0

@Ben - 我相應地更新了我的答案,讓我知道你是否需要任何進一步的細節。 – DanP 2010-11-12 14:39:57

+1

您可以考慮的另一種替代方法:http://fabiomaulo.blogspot.com/2010/07/enhanced-query-object.html我有興趣在未來的項目中嘗試這個概念。 – DanP 2010-11-12 15:13:10

2

我想出了在年底加入以下到我的通用倉庫接口解決方案:

public IEnumerable<T> FindAll<TRelated>(Specification<T> specification, Expression<Func<T, TRelated>> fetchExpression); 

NHibernate的實施是:

public IEnumerable<Product> FindAll<TRelated>(Specification<Product> specification, Expression<Func<Product, TRelated>> fetchExpression) { 
return session.Query<Product>() 
    .Where(specification.IsSatisfiedBy()) 
     .Fetch(fetchExpression); 

}

我正在使用Linq規格(http://linqspecs.codeplex.com)。

有關詳情請參閱http://blogs.planetcloud.co.uk/mygreatdiscovery/post/Eager-loading-with-NHibernate-LINQ.aspx

然而,正如丹在他的評論中指出,this確實看起來像抽象這些查詢的更好的方法。

+0

考慮進一步封裝您的提取策略;例如,如果您需要熱切地獲取2個引用的實體,會發生什麼情況? – DanP 2010-11-12 18:09:22

+0

@DanP - 好點。我可能會改變這個接受一個Expression >參數。 – 2010-11-12 22:18:33

+0

或一個參數數組:) – DanP 2010-11-12 23:33:48

1

我所做的就是這樣的事情(對不起,C#): 首先,接口:

IQueryable<T> All<T>(params Expression<Func<T, Object>> [] fetchPaths); 

至於實施:

public IQueryable<T> All<T>(params Expression<Func<T, Object>> [] fetchPaths) 
{ 
    var queryable = this.session.Query<T>(); 

    foreach (var fetchPath in fetchPaths) 
    { 
     queryable = queryable.Fetch(fetchPath); 
    } 

    return queryable; 
}