嵌套包含Entity Framework Core。

3

我正在使用EF Core进行我的项目开发。但是我在EF Core中嵌套查询时遇到了一个问题。

我有两个类:

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);

我想查询所有包含PermissionDefinitionEntity和自引用的PermissionGroupDefinitionEntity
我可以使用EF Core来完成吗?

1
你至少不能在一个LINQ语句中完成这个操作。这是一个未知深度的树形扩展,需要递归查询。或者如果你想要整个树,只需查询所有的PermissionGroupDefinitionPermissionDefinition(删除这个多余的Entity后缀),这将填充所有导航属性。 - Gert Arnold
那么,我必须使用递归查询吗?感谢您的支持。 - Minh Mít
但是你能解释一下如何获取整个树吗?我不明白为什么要删除实体后缀?我认为这只是类名。@gert-arnold - Minh Mít
1
删除后缀只是一个建议,它是无用的并且会降低可读性。 - Gert Arnold
感谢您的时间。我认为我会使用递归查询来解决这个问题。 - Minh Mít
2个回答

3

您需要递归加载放置在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

这种方法性能很差,我不建议使用。

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


0

您可以这样使用.ThenInclude(i => ...)

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: 'Include路径'PermissionDefinitions->Group'导致循环。在无跟踪查询中不允许循环;要么使用跟踪查询,要么删除循环。'。当我删除AsNoTracking时,此查询仅返回PermissionDefinitions的第一级。 - Minh Mít
1
哦,我想我误读了问题,我已经编辑了我的答案,你可以试试看,看这样是否解决了你的问题。 - PancakeAlchemist
感谢您的支持。此查询返回最多两级PermissionDefinition。例如,PermissionGroupDefinition => PermissionDefinition => PermissionDefinition。如果我有结构PermissionGroupDefinition => PermissionDefinition => PermissionDefinition => PermissionDefinition,则不起作用。 - Minh Mít

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