C# 实体框架核心:加载完整层次结构

C# 实体框架核心:加载完整层次结构,c#,entity-framework-core,entity-framework-core-2.1,entity-framework-core-2.2,C#,Entity Framework Core,Entity Framework Core 2.1,Entity Framework Core 2.2,有了一个自引用表,以及一个保存父记录id的ParentId属性,我可以做些什么,以便使用ef将其子记录加载到每个父记录中 我想要的是转换这个cte,它将作为集合返回完整的层次结构 var queryString = @" ;WITH cte AS ( SELECT * FROM [dbo].[Folders] _f WHERE _f.[Id] = @id UNION ALL SELECT _c.

有了一个自引用表,以及一个保存父记录id的ParentId属性,我可以做些什么,以便使用ef将其子记录加载到每个父记录中

我想要的是转换这个cte,它将作为集合返回完整的层次结构

var queryString = @"
        ;WITH cte AS (
            SELECT * FROM [dbo].[Folders] _f WHERE _f.[Id] = @id

            UNION ALL

            SELECT _c.* FROM [dbo].[Folders] _c
            INNER JOIN cte _cte
            ON _cte.[Id] = _c.[ParentFolderId]
        )

        SELECT * FROM cte";


return await this.Entities.FromSql(new RawSqlString(queryString), new SqlParameter("id", id)).ToListAsync();
这会以某种方式将孩子的层次结构加载到他们的父母身上,同时保持一次数据库访问的性能

class Folder
{ 
     public int Id { get; set; }
     public int? FolderId { get; set; }
     public Folder Folder { get; set; }
     public IEnumerable<Folder> Children { get; set; }
}
配置关系

builder.Ignore(prop => prop.Folder);
builder.HasOne(prop => prop.Folder).WithMany(prop => prop.Children).HasForeignKey(fk => fk.FolderId);

如果您希望在一个查询中包含整个层次结构,这很容易。只需检索所有文件夹,如果启用更改跟踪,EF将修复所有关系。如果你跑的话

var folders = db.Set<Folder>().ToList();
var folders=db.Set().ToList();

您将拥有整个层次结构,并填充所有导航属性。

EF无法生成此CTE。如果将其与
FromSqlRaw
FromSqlInterpolated
一起使用,EF Core可能能够使用ID来重建层次结构,只要DbContext实体配置正确(关系等),另一个选项是使用
hierarchyid
,而不是自引用和包。查询肯定会更容易、更快。即使您在某个时候决定删除该包,使用
hierarchyid
编写分层SQL查询也会容易得多。我认为EF core的2.x版不提供FromSqlRaw或FromSqlInterpolated。将查看HierarchyId库,谢谢。在2.0中,这两个库都是来自SQL的
,如果使用插值字符串,您必须格外小心,否则您可能会得到很好的SQL注入。这就是为什么在EF Core 3中有两种用于插值或参数化查询的独立方法不完全确定检索所有文件夹是什么意思?我猜你是在谈论查找文件夹中的文件夹吧?
var folders = db.Set<Folder>().ToList();