查询多对一,然后返回 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 将始终只是匹配的彩色汽车。
我有一个实体 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 将始终只是匹配的彩色汽车。