c# - 让所有父母共同拥有孩子
问题描述
我有以下使用 Entity Framework Core 的实体:
public class Parent {
public Int32 ParentId { get; set; }
public virtual Collection<ParentChildren> ParentChildrens { get; set; }
}
public class ParentChildren {
public Int32 ParentId { get; set; }
public Int32 ChildrenId { get; set; }
public virtual Parent Parent { get; set; }
public virtual Children Children { get; set; }
}
public class Children {
public Int32 ChildrenId { get; set; }
public virtual Collection<ParentChildren> ParentChildrens { get; set; }
public virtual Collection<ChildrenLocalization> ChildrenLocalizations { get; set; }
}
public class ChildrenLocalization {
public Int32 ChildrenId { get; set; }
public String Language { get; set; }
public String Name { get; set; }
public virtual Children Children { get; set; }
}
鉴于IQueryable<Parent>
我需要,使用 Linq to Entities lambda 表达式:
- 让所有父母共有的孩子;
- 对于每一个都从with中
Children
获得它的名字。ChildrenLocalization
Language="en"
所以我尝试了以下方法:
var result = context.Parents
.SelectMany(y => y.ParentChildrens)
.GroupBy(y => y.ParentId)
.Where(y =>
context.Parents
.SelectMany(y => y.ParentChildrens)
.Select(z => z.ChildrenId)
.Distinct()
.All(z => y.Any(w => w.ChildrenId == z)))
.SelectMany(y => y)
.Select(y => new {
Id = y.ChildrenId,
Name = y.Children.ChildrenLocalizations.Where(z => z.Language == "en").Select(z => z.Name).FirstOrDefault()
})
.GroupBy(x => x.Id)
.Select(x => x.FirstOrDefault())
.ToList();
这个查询给出了预期的结果,但它似乎太复杂了。
我无法改进它,例如,我需要添加最后一个 GroupBy 才能使其工作。
如何使我的查询更简单?
解决方案
由于您具有多对多关系,因此最好将查询基于(开始)结果实体(Children
),从而避免GroupBy
/Distinct
如果您从另一端(Parent
)开始查询。
所以给定
IQueryable<Parent> parents
并假设您可以访问上下文,查询可以编写如下:
var query = context.Set<Children>()
.Where(c => parents.All(p => p.ParentChildrens.Select(pc => pc.ChildrenId).Contains(c.ChildrenId)))
.Select(c => new
{
Id = c.ChildrenId,
Name = c.ChildrenLocalizations.Where(cl => cl.Language == "en").Select(cl => cl.Name).FirstOrDefault()
});
这很好地转换为单个 SQL。
你从unique Children
开始。对于要求 (2),您只需使用导航属性。要求(1)更复杂(所有总是比任何更难实现),但我认为标准
parents.All(p => p.ParentChildrens.Select(pc => pc.ChildrenId).Contains(c.ChildrenId))
相当直观地代表了所有父母共有的孩子。
推荐阅读
- .net - 从 lambda 函数返回 XML 响应(.Net Core)
- sql - 如何处理表中的架构或存储过程更改日志?
- azure-logic-apps - Azure 逻辑应用获取请求缓存结果
- python - Django中不同应用程序的不同网址
- android - 插页式广告未在 android studio 中运行
- java - 如何在 Apache 后面的 Tomcat 中获取真正的 http 请求?
- javascript - 在模块函数上使用绑定后未定义 this
- gatsby - Gatsby v2 - 使用 Markdown 为页面构建静态 HTML 时出错
- wordpress - WordPress - 使用一体化 wp 迁移插件将站点迁移到 AWS 后登录失败
- laravel - 在 Datatable 中加载 JSON 数据需要很长时间