Entity Framework Core:加载完整层次结构

3

如果有一个自引用表,其中包含一个ParentId属性,该属性保存父记录的ID,我该如何使用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; }
}

等级结构示例
- Main (Id: 1 / ParentId: null) 
     - C1 (2/1) 
           - C11 (4/2) 
                  - C111 (7/4)
           - C12 (5/2)
     - C2 (3/1) 
           - C21 (6/3) 
                  - C211 (8/6)

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

2
EF无法生成此CTE。如果您在FromSqlRawFromSqlInterpolated中使用它,只要DbContext实体正确配置(关系等),EF Core可能能够使用ID重建层次结构。 - undefined
另一个选择是使用hierarchyid而不是自引用和EFCore.SqlServer.HierarchyId包。查询肯定会更容易和更快。即使您决定在某个时候移除该包,使用hierarchyid编写分层SQL查询也会更加轻松。 - undefined
我在EF Core 2.x版本中没有看到FromSqlRaw或FromSqlInterpolated的可用性。我会研究一下HierarchyId库,谢谢。 - user9124444
在2.0版本中,对于这两种情况都是使用FromSql方法,如果你使用插值字符串,就要特别小心,否则可能会导致SQL注入问题。这就是为什么在EF Core 3中,针对插值查询和参数化查询有两个单独的方法。 - undefined
2个回答

3
如果您想在一个查询中获取整个层次结构,那很简单。只需检索所有文件夹,如果启用了更改跟踪,则EF将修复所有关系。例如,如果您只运行
var folders = db.Set<Folder>().ToList();

您将获得整个层次结构,其中所有导航属性都已填充。

不太确定你所说的"检索所有文件夹"是什么意思?我猜你是指查找到的文件夹的子文件夹吧? - user9124444

-2
你可以通过该查询获取整个层次结构:
var hierarchy = db.Set<Folder>().Include(f => f.Children).ToList();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接