我有一个名为Contents的表。内容上有一对多的关系,因此每个内容都可以有父母和孩子。我使用的是EF Code First,因此我的实体Content
具有Id
,ParentId
,Parent
和Children
属性。
现在,我正在建立一个基于ajax的内容树。我有一个简单的操作,它根据parentId
返回一个内容级别的JSON:
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并没有提供任何递归方法,所以我真的不知道从哪里开始。
答案 0 :(得分: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();