基于(包括)子实体返回父实体

Posted

技术标签:

【中文标题】基于(包括)子实体返回父实体【英文标题】:Return parent entities based on (and including) child entities 【发布时间】:2021-06-06 13:54:45 【问题描述】:

我正在尝试根据子实体的属性检索实体列表 - 并包括那些相同的子实体。我正在使用 EntityFramework Core 3.1,但如果有任何更改可以为我解决这个问题,我很乐意升级到 5.x。到目前为止,除了一些非常基本的 CRUD 样板之外,我还没有探索过 EntityFramework,所以我不确定这是否更面向 LINQ 或特定于 EF(核心)。下面是项目中方法的一个高度简化的示例,我将使用该方法最终将数据返回给我的 API 的使用者。

兴趣点 (POI) 有许多历史记录 (History)。 POI 有一个 List<History>,History 有一个 PointID,EF Core 使用它来填充 POI 的 List<History>

以下是我如何获取所有 POI 及其历史记录,其中一个点自某个日期以来首次注册(此方法使用可为空的日期参数)

var result = _context.POIs
            .Where(point => (registeredSince == null || point.RegisteredAt >= registeredSince))
            .Include(point => point.Histories)
            .ToList();

但是,我的问题是.. 然后我将如何根据POIHistory 中的属性仅获得POIs(并包括那些相同的History 记录?)或者,使用例子;我只想返回具有History 记录和areaId == 5POIs(并将这些记录包含在结果中)

如果没有非常深入的 EF 知识,一种方法是:

首先运行查询以返回History 实体,其中history.areaId == 5 并仅选择history.PointId 第二个查询是获取所有POIs,其中id 在上面返回的PointId 列表中 ..包括History where history.areaId == 5(重复)

但是,我会运行其中的一部分两次,这似乎效率低下。基本上,我是否可以有效地使用 LINQ/EF 来获取所有 POIs 其中 history.areaId == 5 (然后只包括那些 History 记录,areaId 为 5)?在我能够缩小结果范围之前,我是否必须编写一些不可避免地加载所有 POI 及其 History 记录的内容,或者 EF 可以愉快地做些什么?

【问题讨论】:

【参考方案1】:

您可以使用 EF Core 5.x 中引入的Filtered include 进行查询 -

var result = _context.POIs
            .Include(p => p.Histories.Where(h => h.areaId == 5))            
            .ToList();

这将返回POI 的列表,其中每个列表仅包含areaId == 5 的历史记录。

编辑: 如果你只想要POIs 中的HistoryareaId == 5,你可以简单地过滤它们-

var result = dbCtx.POIs
        .Include(p => p.Histories.Where(h => h.areaId == 5))
        .Where(p => p.Histories.Any(h => h.areaId == 5))
        .ToList();

【讨论】:

这几乎可以工作,除非我不希望返回没有历史记录的 POI(即我只想返回 .Histories.Where(h => h.areaId == 5) 的 POI)。之后我可以删除所有没有历史记录的 POI,但理想情况下我不希望它们重新开始...... 这正是答案 - 昨天让我难过的是.Any【参考方案2】:

您应该能够使用以下内容:

var result = _context.POIs
    .Include(poi => poi.Histories)
    // Enumerate linked Histories & get the areaId from each into a list)
    // ... then see if that list contains the areaID we're looking for.
    .Where(poi => poi.Histories.Select(h => h.areaId).Contains(areaIdParam))
    .ToList();

【讨论】:

以上是关于基于(包括)子实体返回父实体的主要内容,如果未能解决你的问题,请参考以下文章

Restkit/Core Data 关系映射,实体到相同类型的实体(父/子)

如何更新CoreData中另一个实体的子实体

使用基于属性的过滤子元素集获取核心数据实体

基于子实体的属性构建 OrderBy Lambda 表达式

如何创建一个基于父关系过滤核心数据对象的 NSFetchRequest?

从父实体更新子实体