查询多对一,然后返回 parents

Query on a many to one and then returning the parents

我有一个实体 Person,它有一个实体 Car。汽车实体有多个属性,其中之一就是颜色。我想让所有拥有在颜色列表中选择的所有颜色的汽车的人。 如果一个人有很多车我应该可以这样写

PersonQuery.Include(c => c.Cars).Where(q=>q.Cars.Any(colors=>ListOfColors.Contains(colors.Color)));

我想用 Where 替换 Any,但这是不正确的(!?)。我想念什么?

如果您的期望是将汽车 returned 与每个适用的人一起过滤为仅匹配过滤颜色的汽车,则 EF6 不支持此功能。您的查询将 return 人及其汽车,其中该人具有匹配的颜色,但它会 return 该人的所有汽车。

附带说明:使用 Linq 表达式时,标识符的选择应该只是占位符值(即“x”)或反映正在查询的项目,而不是您要查询的内容。例如,当您写 PersonQuery.Where(c => ... 时,您查询的是“Persons”而不是“Cars”,因此“p”比“c”更容易混淆。展开我们将有 .Where(person => person.Cars.Any(car => ...))

在 EF Core 5 中支持筛选包含:

var persons = context.Persons
   .Include(p => p.Cars
       .Where(c => ListOfColors.Contains(c.Color))
   .Where(p => p.Cars.Any(c=>ListOfColors.Contains(c.Color)))
   .ToList();

在 EF 6 中,您最好选择 Cars,然后您可以构建适用的 Person 列表:

var cars = context.Cars
    .Include(c => c.Person)
    .Where(c => ListOfColors.Contains(c.Color))
    .ToList();
var persons = cars.Select(c => c.Person).ToList();

但是,对这种方法的一个警告是,它只能使用原始 DbContext 来完成,这意味着没有加载 任何 其他数据的 DbContext。如果出于任何原因 DbContext 已经在跟踪另一辆适用人员记录的另一种颜色的汽车,则该汽车将自动与 returned Person 相关联,因此您可以轻松地找到自己没有的奇怪汽车t 匹配。

如果您是 运行 请求范围内的 DbContext 并且希望 100% 安全,您应该考虑预测结果而不是直接处理实体:

var results = context.Persons
    .Where(p => p.Cars.Any(c => ListOfColors.Contains(c.Color)))
    .Select(p => new PersonViewModel
    {
        PersonId = p.Id,
        Name = p.Name,
        MatchingCars = p.Cars
            .Where(c => ListOfColors.Contains(c.Color))
            .Select(c => new CarViewModel
            {
                CarId = c.Id,
                Brand = c.Brand,
                Model = c.Model, 
                // ...
            }).ToList()
    }.ToList();

这确保了数据 returned 将始终只是匹配的彩色汽车。