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

时间:2020-10-02 12:28:25

标签: c# entity-framework-core entity-framework-core-2.1 entity-framework-core-2.2

有一个自引用表,它的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();

通过某种方式将孩子的层次结构加载到他们的父母中,同时保持一次db访问的性能。

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 个答案:

答案 0 :(得分:0)

如果您希望在一个查询中使用整个层次结构,那很容易。只需检索所有文件夹,如果启用了更改跟踪,EF将修复所有关系。 IE(如果您刚刚运行)

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

您将拥有填充所有导航属性的整个层次。

答案 1 :(得分:0)

就这样。

cte

var rawSqlQuery= @"
    ;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";

然后使用LINQ进行过滤。

(await this.Entities.FromSql(
    new RawSqlString(rawSqlQuery), 
    new SqlParameter("@id", id))
 .ToListAsync())
 .SingleOrDefault(f => f.Id == id);