执行延迟查询以识别所有后代?

时间:2016-01-29 17:09:16

标签: c# oracle entity-framework entity-framework-6

所以我有一个简单的表来表示支持动态N级深度的类别和子类别的树。

CategoryID int NOT NULL (PK)
ParentCategoryID int NULLABLE (FK to self)
CategoryName varchar(100) NOT NULL

我的实体(从记忆中输入,抱歉,如果这里有一个愚蠢的错误):

public class Category
{
    public int CategoryId { get; set; }
    public int ParentCategoryId { get; set; }
    public string CategoryName { get; set; }

    public virtual Category ParentCategory { get; set; }
    public IDbSet<Category> ImmediateChildCategories { get; set; }
}

在C#(4.5+)的Entity Framework(6.x)中使用执行延迟的lambda表达式,如何识别作为指定类别后代的所有类别?

我喜欢的伪代码SQL查询是这样的:

SELECT * FROM Category WHERE AnyLevelOfAncestorId = 123;

我希望看到的伪代码EF查询是这样的(分页是为了强调我对执行延迟支持的需求):

_db.Categories.Where(cat => cat.HasAncestor(123)).Skip(1000).Take(25).ToList();

其他详情:

  • 具有NULL ParentCategoryID的类别是树的根节点(可以有几个)。
  • 没有类别会有自己的CategoryID,也没有任何后代的ID作为ParentCategoryID(即没有循环关系,所有关系最终会终止于根节点,尽管我可能会查询更低的ID而不是根节点)
  • 我不确定是否要在结果中包含指定的ID(123)。因此,我会接受任何一种方式的答案,并在我知道是否还要包含特定的答案时根据需要进行调整。

1 个答案:

答案 0 :(得分:2)

我假设您的Category实体类型有一个集合导航属性,用于检索其子类别(通过外键相关)。此导航属性将导致在第一次访问子类别时延迟加载子类别。您可以定义一个方法,在根及其子节点上递归调用此导航属性(例如ChildCategories)。

public static IEnumerable<Category> GetDescendants(Category root)
{
    return root.ChildCategories.Concat(root.ChildCategories.SelectMany(GetDescendants));
}

上述代码的缺点是它会发出一个单独的数据库查询来检索每个父代的子代。我不相信Entity Framework目前支持生成单个递归查询(EF 6.1.3)。相反,我建议你在数据库中定义一个递归视图,它会投射所有类别 - 后代对;将此视图包含为实体数据模型中的实体;然后从LINQ查询中查询或加入它。可以使用DBMS特定技术定义视图。 SQL Server支持recursive CTEsrecent versions of Oracle也是如此。