如何实现递归自连接实体框架?

Posted

技术标签:

【中文标题】如何实现递归自连接实体框架?【英文标题】:How to implement recursive self join entity framework? 【发布时间】:2015-05-18 07:51:16 【问题描述】:

我在数据库中有菜单表,它具有自引用外键,即 ParentID。下面是我的菜单类(DB First Approach)

public partial class Menu

    public Menu()
    
        this.Menu1 = new HashSet<Menu>();
        this.Products = new HashSet<Product>();
    

    public int MenuID  get; set; 
    public string Name  get; set; 
    public Nullable<int> ParentID  get; set; 
    public virtual ICollection<Menu> Menu1  get; set; 
    public virtual Menu Menu2  get; set; 
    public virtual ICollection<Product> Products  get; set; 

我想实现以下的东西,

    我想要使用菜单 id 的整个层次结构,例如“如果我通过 7,那么结果应该是菜单 id 7 的所有子项和子项” 如果我通过了 7,那么我想要菜单 ID 为 7 的所有父级和超级父级。

在发布此问题之前,我在*** 上找到了几篇文章,但他们要求实施代码优先方法。以下是Entity Framework Self Join、Most efficient method of self referencing tree using Entity Framework之前在***上发布的问题

【问题讨论】:

可能的双份:***.com/questions/1308158/… 一个可能的解决方案是通过使用 TSQL 递归查询并返回行的 TVF(表值函数)。 @xanatos :我无法与数据库交互。我有菜单类对象的静态列表。这就是为什么我需要用 EF 来做。 【参考方案1】:

我不确定您是否意识到这一点,但 Menu1 是您的父菜单,而 Menu2 是您的子菜单。 (我建议将 Menu1 和 Menu2 属性都重命名为父级和子级)。

我相信您链接的所有解决方案都有可以用来解决问题的解决方案。


代码示例:

void GetParents(Menu current) 
    dbContext.Entry(current).Reference(m => m.Menu2).Load();
    while (current.Menu2 != null) 
        current = current.Menu2; 
        dbContext.Entry(current).Reference(m => m.Menu2).Load();
    


void GetChildren(Menu current) 
    if (current == null) 
        return;
     else 
        dbContext.Entry(current).Collection(m => m.Menu1).Load();
        foreach (var menu in m.Menu1) 
            GetChildren(menu);
        
    

这样的事情应该可以帮助您获取名为 current 的 Menu 实例的所有父级和所有子级。注意效率很糟糕。但这是一个不同的问题。在我的性能测试表明我的应用程序存在瓶颈之前,我不会优化代码。

有趣的引语:“过早的优化是万恶之源。” - Donald Knuth

【讨论】:

Part i 可以通过以下代码达到父母和孩子最高一级'List childList = db.Menus.Where(m => m.ParentID == menuID).ToList();' .可能有N-Level。我该怎么做? 添加了代码示例。它未经测试,因此您需要在这里和那里进行更改。但这是一般的想法。我重新阅读了您的类定义,对您为什么调用 Nullable ParentId 感到有些困惑?我会假设他们会是你的孩子?但是,如果您的模型说您可以有多个父母和一个孩子,那么您将不得不重命名我的函数。 您的回答帮助我解决了我的问题。我想投票,但我的声誉是 1,所以我做不到,我找不到接受答案或标记正确答案按钮来接受你的答案。 您可能会在向上/向下投票按钮下方看到一个勾号。如果你点击勾号,它会将此答案标记为正确。

以上是关于如何实现递归自连接实体框架?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用实体框架进行递归加载?

如何将一个自定义实体映射到实体框架中的某些数据库表?

如何实现 IDbContextFactory 以用于实体框架数据迁移

如何使用实体框架实现数据库独立性

当使用实体框架作为数据访问层时,如何实现业务逻辑层?

DAL 中的实体框架存储库模式,如何实现更新功能?