使用 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();
将使用正确填充的Parent
和Children
属性加载整个层次结构。
当您只需要加载层次结构的一部分时,就会出现参考文章中描述的问题,由于缺乏类似 CTE 的 LINQ 支持,这很困难。
【讨论】:
Include
也可能不需要,因为导航的目标类型与已加载的类型相同,因此无论如何关系修复都会填充它。
有什么原因不能使用.Where
,或者我遗漏了什么?
@eja 原因是如果你使用Where
,它不会加载一些父母/孩子。 Include
没有帮助,因为它不是递归的。
@pantonis 那是因为代码将整个表格加载到一个平面列表中。要获取树(即根节点列表),您将应用 Where
仅获取根项,但在加载所有实体及其导航属性之后。例如var tree = db.Hierarchy.Include(e => e.Children).ToList().Where(e => e.Parent == null).ToList();
@IvayloDimitrov 即使没有Include
用于跟踪查询,上述内容也适用于 3.0,但对于无跟踪查询似乎已损坏。最有可能通过以下重大更改No-tracking queries no longer perform identity resolution。以上是关于使用 EntityFramework.Core 从自引用表加载完整的层次结构的主要内容,如果未能解决你的问题,请参考以下文章
EntityFramework 7 更名为EntityFramework Core(预发布状态)
第15章 使用EntityFramework Core进行配置和操作数据 I
如何在 EntityFramework Core 中使用部分类和部分 OnModelCreating 方法扩展 DbContext