实体框架过滤器嵌套集合

时间:2015-11-13 13:17:06

标签: c# entity-framework linq entity-framework-6

我有一个实体关系图如下。

ClassEntity

public int id
public int std
public virtual ICollection<StudentEntity> students

StudentEntity

public int id
public string name
public string gender
public virtual ClassEntity class
public virtual StudentAddressEntity studentAddress

StudentAddressEntity

public int id
public string address

我需要上课和男孩。

var classEntity = dbContext.Set<ClassEntity>().Where(t => t.id == classId);
var query = classEntity.Include(c => c.students.Select(s => s.studentAddress))
           .FirstOrDefault(c => c.students.Any(s => s.gender == GenderEnum.Male));

但它正在和所有学生一起回归课堂。如何过滤男生?

4 个答案:

答案 0 :(得分:3)

我过去使用过连接来完成类似的结果。例如,我的帐户有嵌套地址(1:M)。如果我想获得属于特定国家/地区的所有帐户,我会使用以下连接:

(from a in accountRepo.GetAll()
      join aa in accountAddressRepo.GetAll() on a.AccountId equals aa.AccountId
      join ad in addressRepo.GetAll() on aa.AddressId equals ad.AddressId
      where ad.CountryId == codeCountryId
      select a).ToList();

如果您没有使用存储库模式,则可以使用DbContext.Set()替换accountRepo.GetAll()。

在您的情况下,您应该能够加入学生,地址和班级实体,并获得类似的结果。下面的内容对您有用:

(from s in DbContext.Set<StudentEntity>
  join a in DbContext.Set<StudentAddressEntity> on s.studentAddress.id equals a.id
  join c in DbContext.Set<ClassEntity> on s.class.id equals c.id
  where c.std == classId && s.gender== GenderEnum.Male
  select s).ToList();

请注意,这是基于我对您的数据库和实体名称的理解的简单表示。您可能需要稍微调整此查询以使其可编译,但基本的想法应该适合您。请告诉我它是如何为你工作的。

答案 1 :(得分:2)

下面应该只为每个班级加载男生。

var classEntity = testContext.Set<ClassEntity>().Where(t => t.Id == classId);
var classes = classEntity.ToList().Select(c =>
{
    testContext.Entry(c)
    .Collection(p => p.Students)
    .Query()
    .Where(s => s.Gender == GenderEnum.Male)
    .Load();

    return c;
});

答案 2 :(得分:2)

您有意“不能”直接使用EF代理执行此操作。例如,考虑当您尝试拨打SaveChanges()并且ClassEntity.Students中缺少所有女学生时会发生什么!

相反,如果您只是显示数据,通常要做的是投射到匿名类型或DTO,例如: -

var classOnlyMale = dbContext.Set<ClassEntity>()
                             .Where(x => x.Id == classId)
                             .Select(x => new // I'm using an anonymous type here, but you can (and usually should!) project onto a DTO instead
                                          {
                                            // It's usually best to only get the data you actually need!
                                            Id = x.Id
                                            Students = x.Students
                                                        .Where(y => y.Gender == GenderEnum.Male)
                                                        .Select(y => new { Name = y.Name, ... })
                                          });

或者,如果您迫切需要进行更改并保存它们: -

var classOnlyMale = dbContext.Set<ClassEntity>()
                             .Where(x => x.Id == classId)
                             .Select(x => new
                                          {
                                            Class = x,
                                            MaleStudents = x.Students.Where(y => y.Gender == GenderEnum.Male)
                                          });

除非没有办法,否则我强烈推荐前者。如果您对过滤后的数据进行更改并尝试保存,则很容易引入错误。

答案 3 :(得分:0)

根据Manish Kumar的建议,我认为加入是正确的方式。

(from s in DbContext.Set<StudentEntity>
  join a in DbContext.Set<StudentAddressEntity> on s.studentAddress.id equals a.id
  join c in DbContext.Set<ClassEntity> on s.class.id equals c.id
  where c.std == classId && s.gender== GenderEnum.Male
  select s).ToList();