EF Core:渴望加载(.Include)子类别(自我引用)

问题描述 投票:0回答:2

我们有类似的东西

var categories = _context.Categories.Include("Categories1.Categories1.Categories1");

这可以处理和处理深达4级的子类别(现在已足够,但谁知道未来)

有没有更好的方法呢?

更多信息

我们先使用数据库。类别表包含以下列:

  • ID
  • ParentCategoryId < - 这具有Category.Id的外键
entity-framework entity-framework-core
2个回答
1
投票

首先,添加数据注释并使您的属性可读

public partial class Category
{

    public Category()
    {
        this.Children = new HashSet<Category>();
    }

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

    public string WhatEverProperties { get; set; }

    public int ParentCategoryId { get; set; }


    [ForeignKey("ParentCategoryId")]
    [InverseProperty("Category")]
    public Category Parent { get; set; } // name "Category1" as "Parent"

    [InverseProperty("Category")]
    public ICollection<Category> Children { get; set; } // Name it as Children
}

那么,你不需要任何.Include(...)语法来显式加载父对象,它将适用于功能中的任何级别。假设你有一个类别,那么你只需得到它的父母:

category.Parent?.Parent?.Parent....

如果你需要获得级别,请使用扩展名:

public static class CategoryExtensions
{
    public static int Level(this Category category)
    {
        if (category.Parent == null)
        {
            return 0;
        }

        return category.Parent.Level() + 1;
    }

}

还有一件事:以下部分应该已经在您的业务规则层中,以避免加载不必要的对象。

public class CategoryBLLWhatever
{
    var context = new YourContext();
    public IQueryable<Category> RootCategories()
    {
        return context.Categories.Where(x => x.Paerent == null).Include(x => x.Children);
    }

    //Include parent in your query if you need it
    public IQueryable<Category> WhateverQuery(Expression<Func<Category, bool>> filter)
    {
        return context.Categories.Where(filter).Include(x => x.Parent);
    }
}

1
投票

在这种特殊情况下,我认为递归属性可能是一个不错的选择。试图从记忆中做到这一点(多年),表现不会很好。没有延迟加载和没有显式加载。

public class Category {
    public int Id {get; set;}
    // other stuff
    public List<Category> MyChildren {
        get { return _context.Categories.Where(x => x.ParentCategoryId == Id).ToList<Category>(); }
    } 
}

这应该为您提供从给定节点开始的分层图。

var justOne = _context.Categories.FirstOrDefault(x => x.Id = <myval>);

缺点是您必须递归地解析/使用结果,并且可能会以指数方式增长。

澄清:EF不允许在递归中使用_context,仅用于说明目的。在存储库/ UoW或业务层中,您可以使用相同的技术通过具有递归调用方法的方法的属性来“组装”完成的实体。

只是为了好玩,这里是相同的递归技术(但不是作为属性,现在没有时间)。

public class Category       // EF entity
{
    public int Id { get; set; }
    public int ParentId { get; set; }
    public virtual List<Category> MyChildren { get; set; }
}
public static class MVVMCategory
{
    public static Category GetCategory(int id)
    {
        Category result = _context.Categories.FirstOrDefault(x => x.Id == id);

        result.MyChildren = GetChildren(id);

        return result;
    }

    public static List<Category> GetChildren(int id)
    {
        List<Category> result = _context.Categories.Where(x => x.ParentId == id).ToList<Category>();
        foreach (var item in result)
        {
            item.MyChildren = GetChildren(item.Id);
        }
        return result;
    }
}

有一点需要注意。我将虚拟添加到列表中以进行延迟加载,因为我正在“手动”加载子项,可以这么说。

© www.soinside.com 2019 - 2024. All rights reserved.