在实体框架 6 中投影自引用多级实体

Onu*_*lar 5 c# entity-framework entity-framework-6

在实体框架 6 中投影自引用多层实体。

假设我有一个Category实体,如下所示:

public class Category
{
    public int CategoryId { get; set; }
    public int? ParentCategoryId { get; set; }        
    public string Name { get; set; }
    public string Description { get; set; }        

    public virtual Category ParentCategory { get; set; }

    public virtual ICollection<Category> SubCategories { get; set; }
    public virtual ICollection<Product> Products { get; set; }

    public Category()
    {            
        SubCategories = new HashSet<Category>();
        Products = new HashSet<Product>();
    }
}
Run Code Online (Sandbox Code Playgroud)

我想将Category DbSet具有所有层次结构的整体映射到以下 POCO 类(同时包括子类别和父类别的所有可能级别):

public class CategoryView
{
    public int Id { get; set; }
    public int? ParentCategoryId { get; set; }        
    public string Name { get; set; }
    public string Description { get; set; }        

    public CategoryView ParentCategory { get; set; }

    public List<CategoryView> SubCategories { get; set; }

    public int ProductCount { get; set; }

    public Category()
    {            
        SubCategories = new HashSet<CategoryView>();            
    }
}
Run Code Online (Sandbox Code Playgroud)

请记住,单个类别可能具有无限级别的子类别,如下所示:

Category (Level 0)
    SubCategory1 (Level 1)
    SubCategory2
        SubCategory2SubCategory1 (Level 2)
        SubCategory2SubCategory2
            SubCategory2SubCategory2SubCategory1 (Level 3)
            ... (Level N)
    SubCategory3
Run Code Online (Sandbox Code Playgroud)

当尝试使用递归方法创建层次结构时,该方法尝试处理每个类别子类别和父类别,得到,因为由于和之间的关系stackoverflow exception,它卡在第一个类别 ( Category) 和第一个子类别 ( ) 之间。SubCategory1ParentCategorySubCategories

进行这种投影的最佳且优雅的方式是什么(不消除父母)?(或者有没有?)

任何帮助,将不胜感激。

谢谢你,

Iva*_*oev 4

我不能说这是否是最好的或优雅的方式,但它是构建这种结构的非常标准且有效的非递归方式。

首先使用简单的投影加载没有父/子对象链接的所有类别:

var allCategories = db.Categories
    .Select(c => new CategoryView
    {
        Id = c.CategoryId,
        ParentCategoryId = c.ParentCategoryId,
        Name = c.Name,
        Description = c.Description,
        ProductCount = c.Products.Count()
    })
    .ToList();
Run Code Online (Sandbox Code Playgroud)

然后创建一个快速查找数据结构用于CategoryView查找Id

var categoryById = allCategories.ToDictionary(c => c.Id);
Run Code Online (Sandbox Code Playgroud)

然后使用之前准备的数据结构将子类别链接到其父类别:

foreach (var category in allCategories.Where(c => c.ParentCategoryId != null))
{
    category.ParentCategory = categoryById[category.ParentCategoryId.Value];
    category.ParentCategory.SubCategories.Add(category);
}
Run Code Online (Sandbox Code Playgroud)

至此,树形链接就准备好了。根据您的需要。allCategories如果您需要真正的树表示,则返回或 根类别:

return allCategories.Where(c => c.ParentCategoryId == null);
Run Code Online (Sandbox Code Playgroud)

PS 实际上allCategories可以避免该列表,因为categoryById.Values可以达到相同的目的。