【发布时间】:2016-05-07 12:31:20
【问题描述】:
所以我有一个看起来像这样的简单表格来表示支持动态 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+) 的实体框架 (6.x) 中使用延迟执行的 lambda 表达式,我将如何识别作为指定类别后代的所有类别?
我想要的伪代码 SQL 查询是这样的:
SELECT * FROM Category WHERE AnyLevelOfAncestorId = 123;
我希望看到的伪代码 EF 查询是这样的(分页是为了强调我需要执行延迟支持):
_db.Categories.Where(cat => cat.HasAncestor(123)).Skip(1000).Take(25).ToList();
其他细节:
- ParentCategoryID 为 NULL 的类别是树的根节点(可以有多个)。
- 任何类别都不会有自己的 CategoryID 或任何后代的 ID 作为 ParentCategoryID(即没有循环关系和 所有关系 最终终止于根节点,尽管我可能会查询低于根节点的 ID )
- 我不确定是否要在结果中包含指定的 ID (123)。因此,一旦我知道我是否想要包含特定的答案,我会接受任何一种方式的答案并根据需要进行调整。
【问题讨论】:
-
我不相信 EF 支持递归查询的生成。我通常会通过在数据库中定义一个递归视图来解决这个问题,该视图投影所有类别-后代对,然后从 EF 查询或加入该视图。如何定义递归视图取决于 DBMS。 SQL Server 有recursive CTEs;我不了解甲骨文。
-
@Douglas 我有一个 DBA 向我展示了一些 P-SQL 语法,它使用
START WITH、CONNECT BY PRIOR和GROUP BY ROLLUP在单个查询中执行此操作。 EF 没有办法使用这样的结构来投射查询吗?如果必须,我们会将其捆绑在存储过程中,但我希望我们可以避免这种情况,因为维护它们对我们来说是一种痛苦(如果这是我们必须采取的方式,视图也是如此)。 -
显然,较新版本的 Oracle 也支持递归 CTE,所以我建议您使用这些。它们比存储过程更易于维护,并且允许进一步的查询组合(根据您的要求)。
-
推荐递归 CTE 的相关答案:stackoverflow.com/a/11929928/1149773。 Oracle 中的递归:stackoverflow.com/a/4659866/1149773.
-
@Douglas 我认为那些 CTE 链接是我需要的答案。不完全是我正在寻找的东西,但目前看来我正在寻找的东西对于 EF 来说是不可能的。我将编辑您的答案以包含该信息并将其标记为答案。谢谢!
标签: c# oracle entity-framework entity-framework-6