2013-12-11 73 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))