使用 EntityFramework.Core 从自引用表加载完整的层次结构

Posted

技术标签:

【中文标题】使用 EntityFramework.Core 从自引用表加载完整的层次结构【英文标题】:loading a full hierarchy from a self referencing table with EntityFramework.Core 【发布时间】:2017-01-24 12:10:30 【问题描述】:

解释为什么这个问题不同于:EF - multiple includes to eager load hierarchical data. Bad practice?

    如果这是一个不好的做法,可能的重复是一个基于意见的问题,而我的问题往往是关于如何做到这一点的技术解决方案,独立于意见是否是一个好的做法。我将这个决定留给产品负责人、需求工程师、项目经理和想要该功能的客户。 给出的答案要么解释了为什么这是一种不好的做法,要么使用了对我不起作用的方法(使用 Include() 和 ThenInclude() 会产生硬编码的深度,而我需要灵活的深度)。

在当前项目(.NET 核心 web api)中,我尝试从自引用表加载层次结构。

在谷歌上搜索了很多之后,我很惊讶这样的任务(我认为这是微不足道的)似乎并不微不足道。

嗯,我有这张表来形成我的层次结构:


CREATE TABLE [dbo].[Hierarchy] (
    [Id]        INT           IDENTITY (1, 1) NOT NULL,
    [Parent_Id] INT           NULL,
    [Name]      NVARCHAR (50) NOT NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [FK_Hierarchy_Hierarchy] FOREIGN KEY ([Parent_Id]) REFERENCES [dbo].[Hierarchy] ([Id])
);

在 web api 中,我尝试返回完整的层次结构。一件可能特别的事情(可能会有所帮助)是我想加载完整的表格。

我也知道我可以使用预加载和导航属性(对于孩子来说,Parent 和 InverseParent)


_dbContext.Hierarchy.Include(h => h.InverseParent).ThenInclude(h => h.InverseParent)...

这样做的问题是,这将加载硬编码深度(例如,如果我使用 1 个 Include() 和 5 个 ThenInclude(),则为六个级别),但我的层次结构具有灵活的深度。

谁能帮助我,给我一些如何加载完整表的代码(例如,在具有 1 个 DB 调用的最佳场景中加载到内存中),然后让该方法返回完整的层次结构?

【问题讨论】:

你自己尝试过什么?什么语言的代码(没有语言标签)? @Sefe Entity Framework Core 显然是 C#(我认为写“a .NET core web api”会很清楚。到目前为止我已经尝试过的东西也被插入为代码 sn- p. 人们正在按标签过滤他们的问题。您需要为您的问题添加正确的标签。 @Sefe 感谢您的建议。我添加了更多标签。我的最后一个问题得到了回答,尽管它们只被标记了两个标签。有什么建议可以解决我的问题吗? 可能会有所帮助patrickdesjardins.com/blog/… 【参考方案1】:

事实上,由于所谓的 EF(核心)关系修复,加载整个层次结构非常容易。

假设我们有以下模型:

public class Hierarchy

    public int Id  get; set; 
    public string Name  get; set; 
    public Hierarchy Parent  get; set; 
    public ICollection<Hierarchy> Children  get; set; 

然后是下面的代码

var hierarchy = db.Hierarchy.Include(e => e.Children).ToList();

将使用正确填充的ParentChildren 属性加载整个层次结构。

当您只需要加载层次结构的一部分时,就会出现参考文章中描述的问题,由于缺乏类似 CTE 的 LINQ 支持,这很困难。

【讨论】:

Include 也可能不需要,因为导航的目标类型与已加载的类型相同,因此无论如何关系修复都会填充它。 有什么原因不能使用.Where,或者我遗漏了什么? @eja 原因是如果你使用Where,它不会加载一些父母/孩子。 Include 没有帮助,因为它不是递归的。 @pantonis 那是因为代码将整个表格加载到一个平面列表中。要获取树(即根节点列表),您将应用 Where 仅获取根项,但加载所有实体及其导航属性之后。例如var tree = db.Hierarchy.Include(e =&gt; e.Children).ToList().Where(e =&gt; e.Parent == null).ToList(); @IvayloDimitrov 即使没有Include 用于跟踪查询,上述内容也适用于 3.0,但对于无跟踪查询似乎已损坏。最有可能通过以下重大更改No-tracking queries no longer perform identity resolution。

以上是关于使用 EntityFramework.Core 从自引用表加载完整的层次结构的主要内容,如果未能解决你的问题,请参考以下文章

EntityFramework Core 中的映射继承

EntityFramework 7 更名为EntityFramework Core(预发布状态)

第15章 使用EntityFramework Core进行配置和操作数据 I

如何在 EntityFramework Core 中使用部分类和部分 OnModelCreating 方法扩展 DbContext

EntityFramework Core 1.1 AddAttachUpdateRemove方法如何高效使用详解

Entityframework Core 3 linq表达式无法翻译