【问题标题】:Nested include Entity Framework Core嵌套包含实体框架核心
【发布时间】:2021-07-11 01:59:13
【问题描述】:

我正在为我的项目使用 EF Core。我在 EF Core 中遇到嵌套查询问题。

我有 2 节课:

public class PermissionGroupDefinitionEntity : IEntity
{
    public string Name { get; set; }
    public string NormalizedName { get; set; }
    public string DisplayName { get; set; }

    public virtual ICollection<PermissionDefinitionEntity> PermissionDefinitions { get; set; }
}

public class PermissionDefinitionEntity : IEntity
{
    public string Name { get; set; }
    public string NormalizedName { get; set; }
    public string DisplayName { get; set; }

    public bool IsEnabled { get; set; }
    public virtual string GroupName { get; set; }

    public virtual PermissionGroupDefinitionEntity Group { get; set; }
    public virtual ICollection<PermissionDefinitionEntity> Children { get; set; }
}

这是 ApplicationDbContext:

        builder.Entity<PermissionDefinitionEntity>().HasOne(r => r.Group).WithMany(r => r.PermissionDefinitions).OnDelete(DeleteBehavior.Cascade);
        builder.Entity<PermissionDefinitionEntity>().HasOne(r => r.Parent).WithMany(r => r.Children).OnDelete(DeleteBehavior.Cascade);

我想查询所有PermissionGroupDefinitionEntity 包括PermissionDefinitionEntityPermissionDefinitionEntity 的自引用。

我可以用 EF Core 做到这一点吗?

【问题讨论】:

  • 你不能,至少不能在一个 LINQ 语句中。这是一个未知深度的树扩展,需要递归查询。或者,如果您想要整个树,只需查询所有 PermissionGroupDefinitions 和 PermissionDefinitions(删除这个多余的 Entity 后缀),这将填充所有导航属性。
  • 那么,我必须使用递归查询吗?感谢您的支持。
  • 但是你能解释一下我怎样才能得到整棵树吗?我不明白为什么要删除实体后缀?我认为它只是类名。 @gert-arnold
  • stackoverflow.com/a/41837737/861716。删除后缀只是一个建议,没有用,而且会降低可读性。
  • 感谢您的宝贵时间。我想我会使用递归查询来解决这个问题。

标签: c# linq entity-framework-core include nested-queries


【解决方案1】:

您需要递归加载放在PermissionGroupDefinitionEntity 中的PermissionDefinitions

首先,您应该使用以下查询加载所有PermissionGroupDefinitionEntities,包括其子项:

var query = _dbContext.PermissionGroupDefinitionEntity
            .AsNoTracking()
            .Include(p => p.PermissionDefinitions )
            .ThenInclude(p => p.Children)
            .ToListAsync();

由于每个PermissionGroupDefinitionEntity 都有一个PermissionDefinition 列表,因此您需要一个像这样的代码的嵌套循环:

foreach (var PermissionGroupDefinitionEntity in PermissionGroupDefinitionEntities)
{
    foreach (var PermissionDefinitions in PermissionDefinitions)
    {

    }
}

然后在内部循环中你应该调用你的递归函数。

请参阅以下链接(在 Entity Framework Core 中递归获取所有子项的示例)

https://patrickdesjardins.com/blog/how-to-load-hierarchical-structure-with-recursive-with-entity-framework-5

这种方式性能很差,不推荐。

在这种情况下,您似乎必须在 SQL 中编写存储过程以获得更好的性能。

【讨论】:

    【解决方案2】:

    你可以像这样使用.ThenInclude(i =&gt; ...)

    var query = _context.PermissionGroupDefinitionEntity
      .AsNoTracking()
      .Include(i => i.PermissionDefinitions)
          .ThenInclude(i => i.Group)
      .AsQueryable();
    

    编辑:

    var query = _context.PermissionGroupDefinitionEntity
      .AsNoTracking()
      .Include(i => i.PermissionDefinitions)
          .ThenInclude(i => i.Children)
      .AsQueryable();
    

    【讨论】:

    • 感谢您的支持。但是当我使用这个查询时。我收到错误:System.InvalidOperationException:'包含路径'PermissionDefinitions->Group'导致循环。无跟踪查询中不允许循环;要么使用跟踪查询,要么删除循环。'。当我删除 AsNoTracking 时。此查询仅返回第一级 PermissionDefinitions。
    • 哦,我想我看错了这个问题,我已经编辑了我的答案,所以你可以试试看是否能解决你的问题。
    • 感谢您的支持。此查询最多返回两级 PermissionDefinition。作为 PermissionGroupDefinition => PermissionDefinition => PermissionDefinition。如果我有 struct PermissionGroupDefinition => PermissionDefinition => PermissionDefinition => PermissionDefinition 它不起作用。
    猜你喜欢
    • 1970-01-01
    • 2021-06-06
    • 1970-01-01
    • 2023-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-24
    相关资源
    最近更新 更多