2013-12-11 72 views
0

給下一個模型:實體框架:取多個集合與過濾器應用於

public class User{ 
    public int IdUser { get; set;} 
    public virtual ICollection<Project> Projects { get; set;} 
    public virtual ICollection<Exam> Exams { get; set;} 
} 

public class Project{ 
    public int IdProject { get; set;} 
    public bool Current { get; set;} 
    public virtual User { get; set;} 
} 

public class Exam{ 
    public int IdExam { get; set;} 
    public int score { get; set;} 
    public virtual User { get; set;} 
} 

我需要得到項目電流=真考試評分大於4從一個給定的用戶。

當我需要過濾導航屬性,避免把所有的記錄,並在內存中應用濾鏡,接下來我要做的:

IQueryable<Project> = context.Entry(user).Collection(x => x.Projects).Query().Where(n => n.Current).ToList(); 

在這樣,我從數據庫中只有當前帶來項目。避免將所有項目檢索到內存,然後在內存中應用篩選器的其他方式。

所以現在,我想要做同樣的事情(只帶來重要的記錄),但我不知道我怎麼能做到這一點,當我有多個集合。

你能幫我嗎?謝謝!

+0

我覺得你還是獲取完整的數據集,因爲你的天堂」 t刪除了虛擬關鍵字http://stackoverflow.com/a/20358097/150342 – Colin

回答

1

你的資料庫是要與不同類型的對導航屬性過濾器返回實體的方法非常迅速填滿。也許你應該有一個看起來像這樣的方法:

public GetUser(int userid, 
        Expression<System.Func<Project, System.Boolean>> projectFilter, 
        Expression<System.Func<Exam, System.Boolean>> examFilter) 
    { 
     var user = context.Users.Find(userid); 

     context.Entry(user) 
       .Collection(c => c.Projects) 
       .Query() 
       .Where(projectFilter) 
       .Load(); 

     context.Entry(user) 
       .Collection(c => c.Exams) 
       .Query() 
       .Where(examFilter) 
       .Load(); 

     return user 
    } 

你這樣稱呼它:

var userincludingCurrentProjectsAndExamsWithScoresLessThan4 = 
         userRepo.GetUser(id, p => p.Current, e => e.Score > 4) 

而且不要忘了從集合或延遲加載刪除virtual關鍵字會拉整個集合了過濾器之前的數據庫應用:

public class User 
{ 
    public int IdUser { get; set;} 
    public ICollection<Project> Projects { get; set;} 
    public ICollection<Exam> Exams { get; set;} 
} 

編輯 我不得不說,這種部分填充導航屬性的技術對我來說有點有趣。我認爲大多數人所做的工作是將數據投影到DTO或ViewModel中,以實現您正在嘗試做的事情。然後,DTO的可以具有更有意義的屬性名稱。事情是這樣的:

var query = from f in context.Foos.Include(x => x.Bars).Include(y => y.Bazs) 
      select new FooDTO 
      { 
       ID = f.ID, 
       Toms = f.Bars.Where(b => b.Name == "Tom").ToList(), 
       Dicks = f.Bazs.Where(b => b.Name == "Dick").ToList() 
      }; 

string sql = query.ToString();//useful in debugger. Remove once satisfied. 

但是,如果你真的想投射到一個實體,而不是一個DTO你可以這樣做:

var usersWithTomsAndDicksOohErr = 
(from f in context.Foos.Include(x => x.Bars).Include(y => y.Bazs) 
    select new //anonymous. You can't construct entities using LINQ to Entities 
    { 
     ID = f.ID, 
     Toms = f.Bars.Where(b => b.Name == "Tom").ToList(), 
     Dicks = f.Bazs.Where(b => b.Name == "Dick").ToList() 
    }) 
    .AsEnumerable()//moves only the data you want into memory 
    .Select(x => new Foo//now you can construct the entity using Linq to Objects 
    { 
     ID = x.ID, 
     Bars = x.Toms, 
     Bazs = x.Dicks 
    }); 
+0

是的,但通過這種方式,它運行一個查詢來檢索項目,另一個查詢用於檢索考試,不是嗎? –

+0

這是真的。我認爲你需要重新思考你部分填充導航屬性的技巧。看我的編輯 – Colin

+0

你是最棒的@Colin!你已經解決了這個問題!現在我只能用一個查詢來做到這一點!非常感謝你的朋友! –

0

什麼:

var q = context.Set<Project>().Where(x => x.Current && x.User.Exams.Where(y => y.score > 4).Count() > 0) 

或可能

var q = context.Set<Project>().Where(x => x.Current && x.User.Exams.Any(y => y.score > 4))