MVC 5 Entity Framework 6 - 删除嵌套/分层数据
MVC 5 Entity Framework 6 - deleting nested / hierarchical data
我 运行 在处理分层数据并尝试删除具有子节点的节点时遇到了一些麻烦。
我建立了一个类似于this article的示例树,并用一点bootstrap装饰了ul-li项目(添加、删除和编辑图标)。
我现在正在为递归删除而苦苦挣扎,因为我使用的是 IEnumerable(Children),它是 parentNodeID 的逆结果。所以当删除一个节点时,子节点被更新并且系统抛出一个枚举错误(集合已经改变)。几年前我遇到过这样的错误,但我不记得我是如何修复它的。有什么建议吗?
这就是我得到的:
~/Models/Tree.cs
public class Tree
{
[Key]
public int NodeID { get; set; }
[Display(Name ="Element name")]
public string NodeName { get; set; }
[Display(Name ="Element identifier")]
public string NodeIdentifier { get; set; }
public int? ParentNodeID { get; set; }
public virtual Tree Parent { get; set; }
public virtual ICollection<Tree> Children { get; set; }
}
~/Controllers/TreesController.cs
// Partial - only Delete Actions
// GET: Trees/Delete/5
public async Task<ActionResult> Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Tree tree = await db.Trees.FindAsync(id);
if (tree == null)
{
return HttpNotFound();
}
if (tree.Children.Count > 0)
{
ViewBag.HasChildren = true;
}
else
{
ViewBag.HasChildren = false;
}
return View(tree);
}
// POST: Trees/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> DeleteConfirmed(int id)
{
Tree tree = await db.Trees.FindAsync(id);
DeleteRecursive(tree);
db.Trees.Remove(tree);
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
public void DeleteRecursive(Tree tree)
{
foreach(var child in tree.Children)
{
DeleteRecursive(child);
}
db.Trees.Remove(tree);
}
~/Views/Trees/Index.cshtml
<div class="container">
@helper BuildTree(IEnumerable<MVCMusicStore.Models.Tree> tree, int? parentID = null)
{
var nodes = tree.Where(t => t.ParentNodeID == parentID).OrderBy(n => n.NodeIndexOrder);
if (nodes.Any())
{
if (nodes.First().ParentNodeID == null)
{
<ul id="tree">
@foreach (var node in nodes)
{
<li>
@node.NodeIndexOrder - @node.NodeName <a href="@Url.Action("Edit","Trees",new { id = node.NodeID })" data-toggle="tooltip" data-placement="right" title="Bearbeiten"><i class="glyphicon glyphicon-edit"></i></a> <a href="@Url.Action("Delete","Trees",new { id = node.NodeID })" data-toggle="tooltip" data-placement="right" title="Löschen"><i class="glyphicon glyphicon-trash"></i></a>
@BuildTree(tree, node.NodeID)
</li>
}
</ul>
}
else
{
<ul>
@foreach (var node in nodes)
{
<li>
@node.NodeIndexOrder - @node.NodeName <a href="@Url.Action("Edit","Trees",new { id = node.NodeID })" data-toggle="tooltip" data-placement="right" title="Bearbeiten"><i class="glyphicon glyphicon-edit"></i></a> <a href="@Url.Action("Delete","Trees",new { id = node.NodeID })" data-toggle="tooltip" data-placement="right" title="Löschen"><i class="glyphicon glyphicon-trash"></i></a>
@BuildTree(tree, node.NodeID)
</li>
}
</ul>
}
}
else
{
<p>
<a href="@Url.Action("Create","Trees", new { parentNodeID = parentID })" data-toggle="tooltip" data-placement="right" title="Neu"><i class="glyphicon glyphicon-plus"></i></a>
</p>
}
}
@BuildTree(Model,null)
</div>
编辑 - 解决方案:
public void DeleteRecursive(Tree tree)
{
foreach(var child in tree.Children.ToArray<Tree>())
{
DeleteRecursive(child);
}
db.Trees.Remove(tree);
}
使用数组进行删除不会改变原始集合。
public void DeleteRecursive(Tree tree)
{
foreach(var child in tree.Children.ToArray<Tree>())
{
DeleteRecursive(child);
}
db.Trees.Remove(tree);
}
使用数组进行删除不会改变原始集合。
我 运行 在处理分层数据并尝试删除具有子节点的节点时遇到了一些麻烦。
我建立了一个类似于this article的示例树,并用一点bootstrap装饰了ul-li项目(添加、删除和编辑图标)。
我现在正在为递归删除而苦苦挣扎,因为我使用的是 IEnumerable(Children),它是 parentNodeID 的逆结果。所以当删除一个节点时,子节点被更新并且系统抛出一个枚举错误(集合已经改变)。几年前我遇到过这样的错误,但我不记得我是如何修复它的。有什么建议吗?
这就是我得到的:
~/Models/Tree.cs
public class Tree
{
[Key]
public int NodeID { get; set; }
[Display(Name ="Element name")]
public string NodeName { get; set; }
[Display(Name ="Element identifier")]
public string NodeIdentifier { get; set; }
public int? ParentNodeID { get; set; }
public virtual Tree Parent { get; set; }
public virtual ICollection<Tree> Children { get; set; }
}
~/Controllers/TreesController.cs
// Partial - only Delete Actions
// GET: Trees/Delete/5
public async Task<ActionResult> Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Tree tree = await db.Trees.FindAsync(id);
if (tree == null)
{
return HttpNotFound();
}
if (tree.Children.Count > 0)
{
ViewBag.HasChildren = true;
}
else
{
ViewBag.HasChildren = false;
}
return View(tree);
}
// POST: Trees/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> DeleteConfirmed(int id)
{
Tree tree = await db.Trees.FindAsync(id);
DeleteRecursive(tree);
db.Trees.Remove(tree);
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
public void DeleteRecursive(Tree tree)
{
foreach(var child in tree.Children)
{
DeleteRecursive(child);
}
db.Trees.Remove(tree);
}
~/Views/Trees/Index.cshtml
<div class="container">
@helper BuildTree(IEnumerable<MVCMusicStore.Models.Tree> tree, int? parentID = null)
{
var nodes = tree.Where(t => t.ParentNodeID == parentID).OrderBy(n => n.NodeIndexOrder);
if (nodes.Any())
{
if (nodes.First().ParentNodeID == null)
{
<ul id="tree">
@foreach (var node in nodes)
{
<li>
@node.NodeIndexOrder - @node.NodeName <a href="@Url.Action("Edit","Trees",new { id = node.NodeID })" data-toggle="tooltip" data-placement="right" title="Bearbeiten"><i class="glyphicon glyphicon-edit"></i></a> <a href="@Url.Action("Delete","Trees",new { id = node.NodeID })" data-toggle="tooltip" data-placement="right" title="Löschen"><i class="glyphicon glyphicon-trash"></i></a>
@BuildTree(tree, node.NodeID)
</li>
}
</ul>
}
else
{
<ul>
@foreach (var node in nodes)
{
<li>
@node.NodeIndexOrder - @node.NodeName <a href="@Url.Action("Edit","Trees",new { id = node.NodeID })" data-toggle="tooltip" data-placement="right" title="Bearbeiten"><i class="glyphicon glyphicon-edit"></i></a> <a href="@Url.Action("Delete","Trees",new { id = node.NodeID })" data-toggle="tooltip" data-placement="right" title="Löschen"><i class="glyphicon glyphicon-trash"></i></a>
@BuildTree(tree, node.NodeID)
</li>
}
</ul>
}
}
else
{
<p>
<a href="@Url.Action("Create","Trees", new { parentNodeID = parentID })" data-toggle="tooltip" data-placement="right" title="Neu"><i class="glyphicon glyphicon-plus"></i></a>
</p>
}
}
@BuildTree(Model,null)
</div>
编辑 - 解决方案:
public void DeleteRecursive(Tree tree)
{
foreach(var child in tree.Children.ToArray<Tree>())
{
DeleteRecursive(child);
}
db.Trees.Remove(tree);
}
使用数组进行删除不会改变原始集合。
public void DeleteRecursive(Tree tree)
{
foreach(var child in tree.Children.ToArray<Tree>())
{
DeleteRecursive(child);
}
db.Trees.Remove(tree);
}
使用数组进行删除不会改变原始集合。