2011-12-08 193 views
6

如果我有一個查詢,看起來像這樣:實體框架包括凡

var forms = repo.GetForms().Where(f => f.SubForms.Any(sf => sf.Classes.Any(c => c.TermId == termId))); 

從這裏就可以看到我的架構如下:

SubForm有很多Class其中有許多Term

我想要什麼:

所有SubForms他們Classes在特定Term

現在發生的事情是,我得到的是具有特定Term任何Class所有SubForm。這意味着SubForm回來了全部孩子Class而不僅僅是與Term有關的。

例如,我有2個學期,每個學期有2個班。這個查詢在該特定術語中帶回4個類而不是2個。

有什麼Include('Expression'),我可以用它來說我只想包括所有基於條件的類?或者是我的查詢錯誤?

+0

第一個'Any'應該是'Where',對吧?否則,你的查詢只會返回一個'bool',並且說:「是否有任何具有給定termId的類的子類,是或否? – Slauma

+0

@Slauma對不起,這個表達式上還有另外一個關卡,我會編輯它,對不起 –

回答

0

我不知道關係的確切名稱,但它應該是沿Include(Where Expression)不存在的

repo.Terms 
    .Include("Classes") 
    .Include("Classes.SubForms") 
    .SingleOrDefault(x => x.TermId = termId); 

// or 

repo.GetSubForms 
    .Include("Classes") 
    .Where(sf => sf.Classes.Where(c => c.TermId == termId)); 
4

線的東西。如果您使用Include的加載方式,您將始終加載所有元素。

通過使用投影可以解決這個問題。基本的想法是,你將選擇一個新的匿名類型與你想要的財產和另一個屬性與過濾的導航項目。 EF會將這些鏈接在一起,因此您將僞造一個Include(Where ...)

Check this for an example

+1

Minor nit:'Include(Expression)'確實存在System.Data.Entity.DbExtensions.Include擴展方法,但是有一個完全不同的含義。它用作字符串文字的替代方法:'repo.Terms.Include(term => term.Classes)'。 – hvd

+0

Thnx。我修改了我的答案 –

0

這似乎是一個常見的要求,今年早些時候我很難找到解決方案。我最終使用了下面鏈接中包含的解決方案(我不確定這是我找到的確切解決方案,但它是相同的想法)。希望這可以幫助!

Filter the "Includes" table on Entity Framework query

   //Found this method to filter our child objects instead of using .include() 
       var Results = (from res in 
            (from u in DataContext.User 
            where u.Type.ToUpper() != "ADMIN" 
            && u.StartDate <= DateTime.Now 
            && (u.EndDate == null || u.EndDate >= DateTime.Now) 
            select new 
            { 
             User = u, 
             Access = u.Access.Where(a => a.StartDate <= DateTime.Now 
                && (a.EndDate == null || a.EndDate >= DateTime.Now)) 
            } 
            ) 
           select res); 

       //The ToArray is neccesary otherwise the Access is not populated in the Users 
       ReturnValue = Results.ToArray().Select(x => x.User).ToList(); 
6

使用此:

var subForms = repo.GetSubForms.Select(sf = new { 
     SubForm = sf, 
     Classes = sf.Classes.Where(c => c.TermId == termId) 
    }).ToList() 
    .Select(t => t.SubForm) 
    .ToList(); 

UPDATE:基於@ Slauma的評論:

如果要加載SubForm s表示他們有任何Class一個TermtermId,你可以從結束開始;像這樣:

var subForms = repo.Terms.Where(t => t.Id == termId).Select(t => new { 
     Term = t, 
     Class = t.Class, 
     SubForm = t.Class.SubForm 
    }).ToList() 
    .Select(t => t.SubForm).ToList(); 

或以最簡單的方式,你可以在你Term使用Include,請參閱:

var subForms = repo.Terms.Include("Class.SubForm").Where(t => t.Id == termId) 
        .Select(t => t.Class.SubForm).ToList(); 

注:我可以從你的問題明白了,你有關係是這樣的:

SubForm has_many Class has_many Term 

但是,您提供的代碼顯示ar elationship像這樣的:

SubForm has_many Class 
Term has_many Class 

如果可以,把有問題的實體,或解釋他們的關係更請。謝謝。

+1

您仍然需要'GetSubForms'和'Select'之間的過濾器:'Where(sf => sf.Classes.Any(c => c.TermId == termId))''。否則,您可以從數據庫加載* all *子表單,包括具有不匹配termId的類的子表單。 – Slauma

+0

@Slauma好的,我完全不明白這個問題;所以我更新我的答案;謝謝:) –

+1

沒錯,問題中的第一個「任何」都令人困惑。我剛纔在這個問題上寫了一條評論,因爲我相信他的意思實際上是一個「Where」。 – Slauma

1

你知道我有時候會開始迷失在漂亮的LINQ擴展方法中,試圖弄清楚如何熱切地加載我想要的東西並訴諸於一個非常簡單的「加入」概念。

var result = 
(from f in SubForums 
from c in Classes 
from t in Term 
where t.TermId = 1 
select new { SubForum = f, Class = c, Term = t }).ToList(); 

這是一個使用預定義導航屬性的簡單連接(因此您不必指定連接條件)。你返回一個你需要的所有東西的匿名類型。這樣做的好處是Entity Framework會爲你做自動修復,因此如果你願意,你可以自由地從你的方法中返回SubForum,它將自動包含Class和後續Term引用。