2

我有一个名为 Contents 的表。Contents 上存在一对多关系,因此每个内容都可以有一个父级和一个子级。我使用的是 EF Code First,所以我有一个Content具有IdParentId和属性Parent的实体。Children

现在,我正在构建一个基于 ajax 的目录树。我有一个简单的操作,它基于以下内容返回一级内容的 JSON parentId

public JsonResult GetContents(int? parentId = null)
{
    return Json(db.Contents
        .Where(p => p.ParentId == parentId)
        .Select(p => new
        {
            id = p.Id,
            name = p.Name
        });
}

我想做的下一件事是自动选择一些值。问题是该值可能在树的层次结构中很深,因此对于每个内容,我需要知道所选值是子还是孙等。

public JsonResult GetContents(int? parentId = null, int selectedValue)
{
    return Json(db.Contents
        .Where(p => p.ParentId == parentId)
        .Select(p => new
        {
            id = p.Id,
            name = p.Name
            isSelectedValueUnderThisHierarchy: // How can I efficiently implement this? 
        });
}

使用大量查询很容易实现,但我正在努力使事情尽可能高效,据我所知,EF 没有提供任何递归方法,所以我真的不知道从哪里开始。

4

1 回答 1

1

您可以首先根据所选值构建所有 ParentId 的列表。根据 Contents 表的大小,您可以先加载数据,然后循环遍历而不对数据库进行额外查询。

db.Contents.Load();
var selectedItem = db.Contents.Find(selectedValue);

var parents = new List<int>();
while (selectedItem.ParentId != null)
{
    parents.Add(selectedItem.ParentId.Value);
    selectedItem = selectedItem.Parent;
}    

或者,您可以使用 CTE(通用表表达式)。

var parents = db.Database.SqlQuery<int>("sql statement");

获得父母列表后,您可以使用Contains.

return Json(db.Contents
    .Where(p => p.ParentId == parentId)
    .Select(p => new
    {
        id = p.Id,
        name = p.Name
        isSelectedValueUnderThisHierarchy = p.ParentId.HasValue && parents.Contains(p.ParentId.Value)
    });

更新:CTE 示例

您可能想要使用存储过程,但这段代码应该可以工作。

var sql = @"with CTE as
    (
        select ParentId
        from Contents
        where Id = {0}
        union all
        select Contents.ParentId
        from Contents
            inner join CTE on Contents.Id = CTE.ParentId    
    )

    select *
    from CTE
    where ParentId is not null";
var parents = db.Database.SqlQuery<int>(string.Format(sql, selectedItem)).ToList();
于 2013-08-22T18:56:52.320 回答