# 以 EF 核心和 PostgreSQL @(}Overview) 管理等级数据

<!--category-- Entity Framework, PostgreSQL, EF Hierarchies -->
<datetime class="hidden">2025-12-06T09:00</datetime>

## 一. 导言导言 导言 导言 导言

在软件开发中,等级数据无处不在 :}(线性评论),}组织图表 *,}文件系统 <,}产品类别\,}♪和论坛讨论 [有关这个话题的首篇文章,](/blog/1188)以及基本挑战依然如故,

### 为何SQL的等级结构很困难

基本问题在于: **相关数据库在数组中思考@, @% 而不是树**Joe Celko在他的杰出著作中解释, [以一组思考](https://www.amazon.com/Joe-Celkos-Thinking-Sets-Management/dp/0123741378),SQL在整张表格上运行 *,}不是单行=.*

当您写入 SQL 查询\ ,}数据库引擎运行时 *一组行*100"或"join客户购买的订单

但等级制度是内在的 *连续循环*找到一个节点的所有子孙 您需要到 :

1. 寻找直系子女
2. 每个孩子都能找到 *他们的* 儿童子女
3. 重复一遍,直到你踏遍了整个树下

此递归的十字路由 @ ' @ t映射为自然设置操作@ MS K1} 您可以在任何深度表达 @ I"} 将我所有的子孙都递解成一个单一的\ ,简单的 SQL 语句, 其中不包含 @ MPK6}

- [递续 CTE](https://www.postgresql.org/docs/current/queries-with.html#QUERIES-WITH-RECURSIVE) (+SQL:1999,+但计算成本昂贵
- 多次往返访问数据库
- 预先计算关系的聪明的去正常化

在本系列中,每种方法都代表了一种不同的交易 -Q 。 在复杂的写法\ ,Q 读起复杂的事情\ MS K2QQ 和存储的间接费用\ MSSK3Q 之间有一个不同的交易。 没有免费的午餐\ I-Q你='ZARE总是以一个价格换另一个#.}请见Joe Celko'Qs. [SQL 中用于智能的树和层次](https://www.amazon.com/Hierarchies-Smarties-Kaufmann-Management-Systems/dp/0123877334)深入地涵盖所有这些方针的,*}.

[TOC]

## 示例\:串列注释

要比较混凝土@, @ we'}将使用线性评论作为我们运行中的示例 @-这个博客就使用了{.}。 批注线索可能看起来像此:}

```mermaid
flowchart TD
    subgraph Post["Post: How to Deploy Docker Containers"]
        C1["Comment 1: Great article!<br/>depth 0"]
        C2["Comment 2: Thanks!<br/>depth 1"]
        C3["Comment 3: Very helpful indeed<br/>depth 1"]
        C4["Comment 4: Agreed!<br/>depth 2"]
        C5["Comment 5: What about Kubernetes?<br/>depth 0"]
        C6["Comment 6: That's covered in part 2<br/>depth 1"]
    end

    C1 --> C2
    C1 --> C3
    C3 --> C4
    C5 --> C6

    style Post stroke:#10b981,stroke-width:2px
    style C1 stroke:#6366f1,stroke-width:2px
    style C2 stroke:#8b5cf6,stroke-width:2px
    style C3 stroke:#8b5cf6,stroke-width:2px
    style C4 stroke:#a855f7,stroke-width:2px
    style C5 stroke:#6366f1,stroke-width:2px
    style C6 stroke:#8b5cf6,stroke-width:2px
```

我们需要支持这些行动

- **获取所有文章的备注** @(#有线条结构保存 #)#
- **把所有祖先都带走** @(_breadcrumb track_)}评论中的评论
- **把所有后代都带走** @(_entire subtree@)}评论中的评论
- **添加新注释** @( 作为对现有评论的回复@)
- **删除子树** @(remove 一项评论和所有答复@)
- **移动子树** @(@ recrown a 批注 *%s K1}稀有的,}但有时需要

## 五方针

每种方针都在其文章中详细论述,

---


### -=YTET -伊甸园字幕组=- 翻译:

**[阅读整条](/blog/efcore-hierarchical-data-adjacency)**

最简单和最直观的方法\.每个行商店都引用其父节点@.\"It'" 大多数开发者首先达到什么目的, 因为它自然地映射到我们对等级的思考方式\.

**如何运作?** 每条评论均无效 `ParentCommentId` “.” 列中根注有 NULL=,}回答指向他们的父@.}

**最好的为:** 当您想要 EF Core@' @%s 导航属性自然工作时, shall 级别为 @ 5-6 @ level@ MS K2 @ 经常在子树下移动\ , @

**交易 ** 要获得祖先或后代,需要循环性幼儿保育或多个查询@. 简单写 @, 读深树可能较慢@MS K2

---


### * 2. 关闭表

**[阅读整条](/blog/efcore-hierarchical-data-closure)**

预估并存储所有祖先的子孙关系, 而不是在查询时间找到对方的关系@,}我们直接保存他们的深度 @.}

**如何运作?** A 单独一 `CommentClosure` 在“1”评论下, Comment@3将包含以下条目: @:+Q(1,4,2), @ @#(3,4,1),_Z(4,4,0).}

**最好的为:** 当您在任意深处需要查询时, 当您很少移动子树@ . k4\ 时, read -\ hiarvy applications\ MS K1\ {}

**交易 ** 更复杂的插入@ ( @% 必须添加关闭条目@ I),} 储存随着深度的增加而增长 *\ MS K2# 移动子树需要重建关闭@ MPK3}

---


### 3. 定義路徑

**[阅读整条](/blog/efcore-hierarchical-data-path)**

将完整的祖先储存为定界的字符串 @. 把它视为存储完整邮政地址,而不仅仅是街道名@.

**如何运作?** 每条评论都有: `Path` 如 {"1/3/7"} 列, 意思是"} root is @1,} 父系是{MS K3} 这是7".} 祖先可以从字符串@;} 子孫中解析 。

**最好的为:** 当对祖先的询问比后代多时... ..."," 当你想要人类的时候..."-\"可读调试路径 . t

**交易 ** 查询要慢一点, 没有正确的索引@ , @ 路径字符串有长度限制 @ MS K1 @ 移动子树需要更新所有后人路径@ I. @

---


### 4.+Nasted 套件

**[阅读整条](/blog/efcore-hierarchical-data-nested)**

从深度中指定每个左节点和右边边界号@ - @ 第一次跨度 @ MS K1}所有后代都有价值 *之间* 父+'%s 边框\ .}

**如何运作?** 每项评论的评论 `Left` 和 `Right` 值Q. 与 L=4, RMS K2 的節点包含所有节点, 其中在 & 4 @\ < 左侧和右侧@< @ @ @\7. 后代端点中找到简单的范围查询@MS K7}

**最好的为:** 读取@ - @ hheavy,} 写下 @ MS K2 @ rarely 假想類似類型樹的區域@ I.} 非常好, @ MPK4} 以顯示的順序將整個子串按下方的排列 * " question\ .}

**交易 ** 插入需要更新很多行@( translate all value 以便让房间 @),}移动子树复杂 *. 不适合经常写入_.}

---


### 5. PostgreSQL 一棵树

**[阅读整条](/blog/efcore-hierarchical-data-ltree)**

PostgreSQL'%s 本地的等级数据扩展@. 类似已实现路径,但有数据库{-} 级别优化和强势模式匹配\.

**如何运作?** 用途和用途 `ltree` 具有像 @"1.3.7". GiST 索引等路径的数据类型,使使用操作员这样的子民查询能够实现高效的祖先{/} `@>` 和 `<@`.

**最好的为:** PostgreSQL-}只允许在性能很重要的地方部署@ ,}当您需要模式匹配查询时 @ MS K2} 当您想要最佳的已实现路径\ .}

**交易 ** PostgreSQL @ MSKK0 @ 仅@ just\ MS K1} 添加数据库扩展依赖性@ . notte @ MPK3 [Npgsql 服务提供商支持 LINQ 翻译](https://www.npgsql.org/efcore/mapping/translations.html#ltree-functions) 树的果实, `LTree` 类型@, @}虽然循环 CTE仍然需要原始 SQL.}

---


## 比较对比摘要

|Q 移动子树 MS K5Q 存储 @|EF核心支持 #|#
|----------|--------|---------------|-----------------|--------------|---------|-----------------|
| **相邻名单** 和CTE |OO MS K6D)Q 与CTE |O NSK9
| **审结表** @ | @ O(d) @ @ @ I|O#(1) @ (| OMS K6) @ NSK7 O}(s x d□)* * MSk9QQQZOO(nxd)|好?
| **定文件路径** MSKOOO O(1) NSK2 O(1)* |OO(1)QO MS K2ZO I(AS)Q |OMSOK6QD每个節点 MSKO8}好的|
| **括号集** @ | @ OQ(n) @ @ I|OO(1) @ (| OQ(1)) MS K7 OZ(N}) @| Minimal@|好□|#
| **树叶** O|OO) |O(D)+每个节点 @|+好~( `LTree` 类型@) @ @% | @%

*n= 總結節點MS K1 d= 深度 , s @= 子樹的大小*
*使用正确的索引

## 决策流程图

```mermaid
flowchart TD
    Start([Start]) --> Q1{Shallow tree?<br/>< 5 levels}
    Q1 -->|Yes| Q2{Need EF Core<br/>navigation properties?}
    Q2 -->|Yes| AL[Adjacency List]
    Q2 -->|No| Q3{Performance<br/>critical?}
    Q3 -->|No| AL
    Q3 -->|Yes| MP[Materialised Path]

    Q1 -->|No| Q4{Read-heavy?}
    Q4 -->|Yes| Q5{Writes rare?}
    Q5 -->|Yes| NS[Nested Sets]
    Q5 -->|No| CT[Closure Table]

    Q4 -->|No| Q6{PostgreSQL only?}
    Q6 -->|Yes| LT[ltree]
    Q6 -->|No| Q7{Need breadcrumbs?}
    Q7 -->|Yes| MP
    Q7 -->|No| CT

    style Start stroke:#10b981,stroke-width:2px
    style AL stroke:#6366f1,stroke-width:2px
    style MP stroke:#8b5cf6,stroke-width:2px
    style NS stroke:#ec4899,stroke-width:2px
    style CT stroke:#f59e0b,stroke-width:2px
    style LT stroke:#14b8a6,stroke-width:2px
```

## 真实的-#World choice_:}本博客

这个博客使用 **审结表** 供评论用的“.”方法

1. 阅读意见的次数远多于书面
2. 我们需要高效显示嵌套的批注线索
3. 深度@- @% 限制查询对性能很重要 @ (_ @ we 上限为 @ I5# 深层 @ MPK3}
4. 移动备注是罕见的 @( } moder 偶尔需要做此@ )_ {}

见见 [缩略语](/blog/efcore-hierarchical-data-closure) 完整执行细节@. @%

## 系列导航

- **部分=1:}概览** @(_这篇文章#)}
- [部分=1.1: 相邻列表](/blog/efcore-hierarchical-data-adjacency) - 简单的父引用
- [缩略语](/blog/efcore-hierarchical-data-closure) -预言关系
- [集成路径](/blog/efcore-hierarchical-data-path) -路径字符串
- [{1.4:} 内嵌套件部件](/blog/efcore-hierarchical-data-nested) @ -_ 左边 @ I/} 右邊界
- [部份 @1.5:_ltree](/blog/efcore-hierarchical-data-ltree) - PostgreSQL 本地扩展
- “2:Raw SQL”和“Dapper ‘(’ ”部分即将到来