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

mon*_*nty 11 c# linq entity-framework-core asp.net-core

解释为什么这个问题不同于:EF - 多个包括急切加载分层数据.不好的做法?

  1. 可能的重复是基于意见的问题,如果这是一个不好的做法,而我的问题往往得到如何做的技术解决方案,独立于意见,如果它是一个好的做法.我将此决定留给产品所有者,需求工程师,项目经理和想要该功能的客户.
  2. 给出的答案要么解释为什么它是一个不好的做法,要么使用一种对我不起作用的方法(使用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])
);
Run Code Online (Sandbox Code Playgroud)

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

我也知道我可以使用预先加载和导航属性(子项为Parent和InverseParent)


_dbContext.Hierarchy.Include(h => h.InverseParent).ThenInclude(h => h.InverseParent)...
Run Code Online (Sandbox Code Playgroud)

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

任何人都可以通过给我一些代码来帮助我,如何加载整个表(例如,在1 DB调用的最佳方案中进入内存),然后使该方法返回完整的层次结构?

Iva*_*oev 22

事实上,由于所谓的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; }
}
Run Code Online (Sandbox Code Playgroud)

然后是以下代码

var hierarchy = db.Hierarchy.Include(e => e.Children).ToList();
Run Code Online (Sandbox Code Playgroud)

将加载整个层次与填充正确ParentChildren性能.

当您需要加载层次结构的一部分时,引用的帖子中描述的问题就出现了,由于LINQ中缺少类似CTE的支持,这很难实现.

  • 也可能不需要"包含",因为导航的目标类型与已加载的类型相同,因此无论如何,关系修正都会填充它. (4认同)
  • @pantonis那是因为代码将整个表加载到一个平面列表中。要获取树(即根节点列表),您可以应用“Where”来仅获取根项,但“在”加载所有实体及其导航属性之后。例如 `var tree = db.Hierarchy.Include(e =&gt; e.Children).ToList().Where(e =&gt; e.Parent == null).ToList();` (4认同)
  • @IvayloDimitrov 上面的内容在 3.0 中工作,即使没有用于跟踪查询的“包含”,但对于非跟踪查询似乎会被破坏。最有可能通过以下重大更改[无跟踪查询不再执行身份解析](https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-3.0/writing -更改#notrackingresolution)。 (3认同)
  • 有什么原因不能使用`.Where`,或者我遗漏了什么? (2认同)
  • @eja原因是,如果您使用“哪里”,它将不会加载某些父母/孩子。`include`没有帮助,因为它不是递归的。 (2认同)