如何计算嵌套类别中的项目总数(自引用类别表)

时间:2015-05-07 15:25:26

标签: c# asp.net sql-server entity-framework

我正在使用C#,ASP.Net,Entity Framework,LINQ,Microsoft SQLServer

我有两张桌子

tblCategories
Id
Name
ParentId     (parentId is the Id of another category in this table that is the parent of this one)

tblQuestion
Id
CategoryId
Etc.

所以说我的类别表包含

Programming  (Id 1 ParentId null)     - directly contains 10 questions
     C# (Id 25 ParentId 1)    – directly contains 5 questions
        Interview Questions (Id 99 ParentId 25) - directly contains 2 questions

变量(Id 100 ParentId 25) - 直接包含1个问题     网络(Id 2 Parent Id null)

我想知道每个类别存在多少问题,包括其子类别 换句话说,在这个例子中,18个问题在编程中,8个在C#中

是否可以在查询中执行此操作,还是需要在每个类别上调用某种迭代循环? 例如db.categories.Where(something).count()

这是我的类别类:

public class Category
{

    [Key]
    public int Id { get; set; }

    [StringLength(40)]
    public string Name { get; set; }

    public int? ParentId { get; set; }

    [JsonIgnore]
    public virtual ICollection<Category> Children { get; set; }

    [JsonIgnore]
    public virtual Category Parent { get; set; }

    [JsonIgnore]
    public virtual ICollection<Question> Questions { get; set; }

}

然后在OnModelCreating:

modelBuilder.Entity<Category>()
            .HasMany(x => x.Children)
            .WithOptional(y => y.Parent)
            .HasForeignKey(z => z.ParentId)
            .WillCascadeOnDelete(false);

StackOverflow上有几个类似的问题,如:Help with generating a report from data in a parent-children modellinq aggregated nested count,但我找不到一个足够好的匹配,我能理解

为了澄清,我想知道子类别中的问题数量,而不是儿童类别的数量。

3 个答案:

答案 0 :(得分:3)

我不确定你想要完成什么,但正如其他人指出的那样,简单的Linq无法实现。

  • 如果你想要的是获得一个类别的问题的总数:,你需要:

    var count = TotalQuestions(category1);
    

TotalQuestions方法

 public int TotalQuestions(Category category)
        {
            var totalQuestions = category.Questions.Count;
            foreach (var innerCategory in category.Categories)
            {
                totalQuestions += TotalQuestions(innerCategory);
            }
            return totalQuestions;

            //OR
            //return category.Questions.Count + category.Categories.Sum(innerCategory => TotalQuestions(innerCategory));
        }
  • 如果您想要每个类别的问题总数(包括其子类别的数量),您需要:

    var counts = new Dictionary<Category, int>();        
    TotalQuestions(category1, counts);
    

第二个TotalQuestions方法

private int TotalQuestions(Category category, Dictionary<Category, int> counts)
        {
            if (!counts.ContainsKey(category))
            {
                counts.Add(category, category.Questions.Count);
            }

            foreach (var innerCategory in category.Categories)
            {
                counts[category] += TotalQuestions(innerCategory, counts);
            }

            return counts[category];
        }

<强>示例

对于此示例数据:

        var category1 = new Category(1, "Cat1", null);
        var category2 = new Category(1, "Cat2", category1);
        var category3 = new Category(1, "Cat3", category2);
        var category4 = new Category(1, "Cat4", category2);
        var category5 = new Category(1, "Cat5", category3);

        category1.Questions.Add(new Question("q1"));
        category1.Questions.Add(new Question("q2"));
        category1.Questions.Add(new Question("q3"));
        category1.Questions.Add(new Question("q4"));

        category2.Questions.Add(new Question("q1"));
        category2.Questions.Add(new Question("q2"));
        category2.Questions.Add(new Question("q3"));

        category3.Questions.Add(new Question("q1"));
        category3.Questions.Add(new Question("q2"));

        category4.Questions.Add(new Question("q1"));

        category5.Questions.Add(new Question("q1"));
        category5.Questions.Add(new Question("q2"));

        var count = TotalQuestions(category1);
        MessageBox.Show(count.ToString());

        var counts = new Dictionary<Category, int>();
        TotalQuestions(category1, counts);

你得到:

  • 计数 = 12
  • 并且计数
    • category1 =&gt; 12
    • category2 =&gt; 8
    • category3 =&gt; 4
    • category4 =&gt; 1
    • category5 =&gt; 2

答案 1 :(得分:0)

您不能仅使用简单的linq查询进行此类计数,或仅使用fluent调用进行此类计数,以确定您具有可变数量的迭代级别(生成的数量) :父母,孩子,孙子等各种各样)。因此,我建议创建一个递归方法来计算子项:

static void RecursiveQuestionCount(Category cat, ref int count)
{
    count += Questions.Count(); // this cat's questions.
    foreach(var child in cat.Children)
    {
        RecursiveQuestionCount(child, ref count); // will add each child and so it goes...
    }
}

计数结果将存储在ref int count

int catCount;

Foo.RecursiveQuestionCount(existingCategoryObj, catCount);

Console.WriteLine(catCount);

答案 2 :(得分:0)

是的,你需要一个递归方法。

// Recursively counts the number of children of this parent
static int CountChildren(Category parent)
{
    if (parent == null)
        return 0;

    if (parent.Children == null || !parent.Children.Any())
        return 0;

    return parent.Children.Count() 
         + parent.Children.Sum(ch => CountChildren(ch));
}