我正在使用ASP.NET MVC4。我完全不知道从哪里开始-我需要在每个级别(编辑行,创建行,删除行)显示一个完整的带有CRUD操作的分层网格。我在实体框架(.edmx)中使用数据库优先方法。实体之间的关系由数据库中同一行中的“ ParentId”值维护。我希望“删除”功能级联到所有子级,就像在SQL Server中的关系设置一样。
问题:如果我希望使用ParentId来维护层次关系,那么我想从哪里开始进行CRUD操作的层次网格?我研究了ListViews,但我认为这不是我所需要的。除非绝对必要,否则我不想过于复杂,我也不想采用自动售货机。
最佳答案
我最终使用了MvcTreeView(http://mvctreeview.codeplex.com/
)。 Nuget也提供此功能。该Html Helper专门用于与邻接表(通过ParentId列或类似表维护其层次结构的层次表)一起使用。该帮助器为表中的每个记录生成一个层次树视图。此外,您可以通过在每个项目上添加单独的CRUD操作来进一步自定义,并且CRUD的工作方式与带有实体框架项目的普通ASP.NET MVC一样。
要逐步删除“ n”深度树的所有路径,请按以下步骤操作:
我最终创建了一个专门用于邻接表的自定义模块。在SQL中的邻接表中,您具有一个表,该表通过“ ParentId”列维护“ n”深度层次结构,该列是返回同一表中Id列(主键)的外键。
我创建了一个名为“儿童”的帮助程序类。此类的目的是返回给定父级的所有遍历子ID的列表。因此,如果您将Id传递给说6个级别的父级,则下面的代码将遍历所有6个级别,并返回所有孩子,孙子,曾孙等Id的完整列表。
之所以要获得所有孩子的所有Id列表而不是要删除的对象列表,是因为如果我要删除的对象列表必须将这些对象放在不同的DbContext下,因此当我尝试实际删除它们,我将收到一条错误消息,指出该对象已分离(或类似的东西),因为它是在不同的上下文中实例化的。获取ID列表可防止这种情况的发生,我们可以使用相同的上下文执行删除。
因此,从您的代码中调用此方法GetChildrenIds(List<int> immediateChildrenIds)
,并传入与所选节点的直接子代相对应的ints
列表。例如,要获取传递给此方法的直接子级列表,请使用类似以下的内容(它基于使用WebAPI的ASP.NET MVC模式):
// keep in mind that `id` is the `id` of the clicked on node.
// DELETE api/region/5
public HttpResponseMessage Delete(int id)
{
Region region = db.Regions.Find(id);
List<int> tempRegionIds = new List<int>();
List<int> immediateChildrenIds = (from i in db.Regions where i.ParentId == id select i.Id).ToList();
List<int> regionsToDeleteIds = new List<int>();
// the below is needed because we need to add the Id of the clicked on node to make sure it gets deleted as well
regionsToDeleteIds.Add(region.Id);
// we can't make this a static method because that would require static member
// variables, and static member variables persist throughout each recursion
HelperClasses.HandleChildren.Children GetChildren = new HelperClasses.HandleChildren.Children();
// see below this code block for the GetChildrenIds(...) method
tempRegionIds = GetChildren.GetChildrenIds(immediateChildrenIds);
// here, we're just adding to regionsToDeleteIds the children of the traversed parent
foreach (int tempRegionId in tempRegionIds)
{
regionsToDeleteIds.Add(tempRegionId);
}
// reverse the order so it goes youngest to oldest (child to grandparent)
// is it necessary? I don't know honestly. I just wanted to make sure that
// the lowest level child got deleted first (the one that didn't have any children)
regionsToDeleteIds.Reverse(0, regionsToDeleteIds.Count);
if (regionsToDeleteIds == null)
{
return Request.CreateResponse(HttpStatusCode.NotFound);
}
foreach (int regionId in regionsToDeleteIds)
{
// here we're finding the object based on the passed in Id and deleting it
Region deleteRegion = db.Regions.Find(regionId);
db.Regions.Remove(deleteRegion);
}
...
以下代码是返回孩子ID的完整列表的类。我将此代码放在单独的帮助程序类文件中。我说的是DbContext
_db
,当时我说您不想在此上下文下检索对象列表,否则当在您的控制器中实际调用Delete
时,将不起作用。因此,正如您所看到的,我得到了一个Id的列表,并进行了实际的DbContext调用以将对象放入控制器内,而不是此帮助器类内。public class Children
{
private Entities _db = new Entities(HelperClasses.DBHelper.GetConnectionString());
private List<int> _childrenIds = new List<int>();
private List<int> _childRegionIds = new List<int>();
public List<int> GetChildrenIds(List<int> immediateChildrenIds)
{
// traverse the immediate children
foreach (var i in immediateChildrenIds)
{
_childRegionIds.Add(i);
_childrenIds = (from child in _db.Regions where child.ParentId == i select child.Id).ToList();
if (_childrenIds.Any())
GetChildrenIds(_childrenIds);
else
continue;
}
return _childRegionIds;
}
}
关于c# - 在邻接表上具有CRUD操作的分层网格(具有ParentId列的表),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18921397/