如何递归加载所有子记录?

时间:2019-10-13 20:07:48

标签: c# recursion entity-framework-core yield-return

我有这个Project类:

public class Project
{
    public int Id { get; set; }
    public int? ParentId { get; set; }
    public List<Project> ChildProjects { get; set; }
    // more properties
}

这是我尝试加载任何给定项目的所有后代:

private async Task<List<Project>> LoadDescendantsOf(Project project)
{
    project.ChildProjects = await db.Projects
        .Where(p => p.ParentId == project.Id)
        .ToListAsync();
    foreach (Project childProject in project.ChildProjects)
    {
        yield return childProject.ChildProjects = 
            await LoadDescendantsOf(childProject);
    }
}

...但是它不起作用。我收到的错误消息是

  

'ProjectsController.LoadDescendantsOf(Project)'的主体不能是迭代器块,因为'Task>'不是迭代器接口类型

我尝试使该方法同步,但这是相同的错误消息,只是没有“任务”部分。

我如何使其工作?

1 个答案:

答案 0 :(得分:1)

您可以为此编写简单的扩展名:

def main(): 
  input_val = int(input('Enter change: '))
  if input_val <= 0:
    print('Some error message')
  else:
    #the rest of the code you provided 
    num_dollars = input_val // 100
    input_val %= 100
    num_quarters = input_val // 25
    input_val %= 25
    num_dimes = input_val // 10 
    input_val %= 10
    num_nickels = input_val // 5
    input_val %= 5
    num_pennies = input_val

    if num_dollars >1:
        print('%d dollars' % num_dollars)
    elif num_dollars ==1:
        print('%d dollar' % num_dollars)
    if num_quarters > 1:
        print('%d quarters' % num_quarters)
    elif num_quarters ==1:
        print('%d quarter' % num_quarters)
    if num_dimes >1:
        print('%d dimes' % num_dimes)
    elif num_dimes ==1:
        print('%d dime' % num_dimes)
    if num_nickels >1:
        print('%d nickels' % num_nickels)
    elif num_nickels ==1:
        print('%d nickel' % num_nickels)
    if num_pennies >1:
        print('%d pennies' % num_pennies)
    elif num_pennies ==1:
        print('%d penny' % num_pennies)
main()

和用法:

    public static IEnumerable<T> Traverse<T>(this T e, Func<T, IEnumerable<T>> childrenProvider)
    {
        return TraverseMany(new[] { e }, childrenProvider);
    }

    public static IEnumerable<T> TraverseMany<T>(this IEnumerable<T> collection, Func<T, IEnumerable<T>> childrenProvider)
    {
        var stack = new Stack<T>();
        foreach(var c in collection)
        {
            stack.Push(c);
        }
        while (stack.Count > 0)
        {
            var i = stack.Pop();
            yield return i;
            var children = childrenProvider(i);
            if (children != null)
            {
                foreach (var c in children)
                {
                    stack.Push(c);
                }
            }
        }
    }

如果您要加载子项目,我建议为此在游标上编写递归SQL过程,但这也适用于小数据:

var allProjectIds = p.Traverse(x => x.ChildProjects).Select(x => x.Id).ToList();