实体框架:应用过滤器获取多个集合

时间:2013-12-11 16:15:36

标签: .net entity-framework ef-code-first

给出下一个模型:

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();

就这样,我从数据库中只带来了当前的项目。避免将所有项目检索到内存中的其他方法,然后在内存上应用过滤器。

所以现在,我想做同样的事情(只带上重要的记录),但我不知道如果我有多个集合,我怎么能这样做。

你能帮帮我吗?谢谢!

2 个答案:

答案 0 :(得分: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或ViewModels中以实现您想要做的事情。然后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
    });

答案 1 :(得分: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))