Projecting self-referenced multilevel objects in Entity Framework 6

Projecting independent references to multilevel objects in Entity Framework 6.

Let's say that I have an object Categoryas follows:

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

And I would like to map the whole Category DbSetwith the entire hierarchy to the following POCO class (including all possible levels of child and parent categories):

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

Please keep in mind that one category can have an unlimited number of subcategories as follows:

Category (Level 0)
    SubCategory1 (Level 1)
    SubCategory2
        SubCategory2SubCategory1 (Level 2)
        SubCategory2SubCategory2
            SubCategory2SubCategory2SubCategory1 (Level 3)
            ... (Level N)
    SubCategory3

, , stackoverflow exception, (Category) (SubCategory1) - ParentCategory SubCategories.

( )? ( ?)

.

,

+4
2

, , .

/ , :

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

CategoryView Id:

var categoryById = allCategories.ToDictionary(c => c.Id);

, :

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

. . allCategories , :

return allCategories.Where(c => c.ParentCategoryId == null);

P.S. allCategories , categoryById.Values .

+3

, IDictionary<int, CategoryView>. Category CategoryView, , , , CategoryView. . , .

, CategoryView Category. , CategoryView, .

public class CategoryView
{

    public int Id { get; set; }

    public int? ParentCategoryId { get; set; }        

    // other properties ...

    public CategoryView ParentCategory { get; set; }

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

    public int ProductCount { get; set; }

    public CategoryView()
    {            
        SubCategories = new List<CategoryView>();
    }
}
+2

Source: https://habr.com/ru/post/1666238/


All Articles