2011-08-16 109 views
19

這裏是問題: 我需要返回具有過濾嵌套集合的對象的集合。 例如:有一個有訂單的商店,我需要返回一個商店集合,其中包含帶訂單的嵌套集合,但沒有標記爲已刪除的客戶訂單。如何篩選嵌套的集合實體框架對象?

這是我試圖做的。但仍然沒有運氣。任何建議appriciated :)

public List<StoreEntity> GetStores(Func<Store, bool> storeFilter, Predicate<OrderEntity> orderFileter) 
{ 
    IQueryable<StoreEntity> storeEntities = Context.Stores 
     .Include(o => o.Order) 
     .Include(cu => cu.Orders.Select(c => c.Customer)) 
     .Where(storeFilter) 
     //.Where(rcu=>rcu.Orders.Select(cu=>cu.Customer.Deleted==false)) //just test this doesn't work 
     .AsQueryable(); 

    List<StoreEntity> storeEntities = storeEntities.ToList(); 

    //storeEntities.ForEach(s => s.Orders.ToList().RemoveAll(c=>c.Customer.Deleted==true)); // doesn't work 

    foreach (StoreEntity storeEntity in storeEntities) 
    { 
     storeEntity.Orders.ToList().RemoveAll(r=>r.Customer.Deleted==true); 
    } 

    return storeEntities; 
} 

問題是,該過濾器沒有應用。已將刪除標誌設置爲true的客戶留在集合中。

+0

問題是什麼?不編譯?它會拋出一個運行時異常嗎?它運行但返回錯誤的數據? –

+0

解釋了一點。謝謝。 –

+1

我最終使用了這個nuget包:'Z.EntityFramework.Plus.QueryIncludeFilter.EF6'文檔在這裏:https://github.com/zzzprojects/EntityFramework-Plus/wiki/EF-Query-IncludeFilter-%7C-Entity- Framework-Include-Related-Entities-using-Where-Filter –

回答

26

你不能直接以「整潔」的方式做到這一點,但你有幾個選擇。
首先,你可以顯式地在你提取商店後加載子集合。請參閱Applying filters when explicitly loading related entities部分。

如果您不想額外訪問數據庫,則必須構建自己的查詢並手動將父集合和過濾後的子集合投影到另一個對象上。請參見以下問題的例子:
Linq To Entities - how to filter on child entities
LINQ Query - how sort and filter on eager fetch

編輯

順便說一句,你的第一個嘗試.Where(rcu=>rcu.Orders.Select(cu=>cu.Customer.Deleted==false))不會因爲這樣你申請一個過濾器,你的父母收集工作(商店)而不是嵌套集合(例如所有沒有刪除客戶的商店)。
邏輯上,過濾嵌套集合的代碼應放置在Include方法中。目前,Include僅支持Select說法,但我個人認爲這是時間EF團隊實施類似:

.Include(cu => cu.Orders.Select(c => c.Customers.Where(cust => !cust.IsDeleted))); 
+0

是的,我同意。 (我知道這件事不起作用,但仍想嘗試一下,誰知道這個功能是隱藏的,我會驚喜地發現),是的,這種包含會很好。我決定去用自定義投影......不太喜歡這種方法,因爲我不得不分配很多愚蠢的值,如(ID = r.ID,Name = r.Name ...等等)。但至少它的作品:) Thx –

+3

我同意英孚團隊應該實施過濾包括。爲此投票[這裏](https://entityframework.codeplex.com/workitem/47)! – Chris

+0

如果我有一個稱爲通用方法 'GetWithInclude()' '公共的IQueryable GetWithInclude(PARAMS表達> [] includeProperties) { 返回includeProperties.Aggregate <表達式>,IQueryable >(DbSet, (current,includeProperty)=> current.Include(includeProperty)); }' 然而,我沒有一個集合,我需要從投影過濾。換句話說,我有一個需要等同的東西。 – Vyache

2

與你目前擁有的代碼的問題是這一行:

storeEntity.Orders.ToList().RemoveAll(r=>r.Customer.Deleted==true); 

storeEntity.Orders.ToList()返回一個新的List<OrderEntity>storeEntity.Orders的內容。從這個新列表中,您可以刪除所有已刪除的客戶。但是,此列表在此之後不會被使用。

但是,即使它能做到你想做的,也會從數據庫中刪除那些客戶,因爲你的StoreEntity對象仍然連接到數據上下文!

您真的想要在註釋Where中首次嘗試使用過濾器。請看Yakimych的答案。

-5

老話題,但我遇到了一個相當類似的問題。我搜索了很多,並且Yakimych提供的MSDN鏈接最終暗示我有一個解決方案:明確禁用延遲加載,然後執行查詢來過濾導航屬性。結果將被「附加」到主要查詢中,這會給出類似的結果:

Context.Configuration.LazyLoadingEnabled = false; 

var filteredOrders = Context.Orders.Where(x => x.Customer.Delete == false); 

IQueryable<StoreEntity> storeEntities = Context.Stores 
.Include(o => o.Order) 
.Include(cu => cu.Orders.Select(c => c.Customer)) 
.Where(storeFilter) 
.AsQueryable(); 
+0

什麼是storeFilter? –