1

Ich habe einige Probleme bekommen, als ich mit hierarchischen Daten herumspielte und versuchte, einen Knoten zu löschen, der untergeordnete Elemente hat.MVC 5 Entity Framework 6 - Löschen verschachtelter/hierarchischer Daten

Ich habe einen Beispielbaum ähnlich this article eingerichtet und die ul-li Elemente mit ein wenig Bootstrap (Hinzufügen, Löschen und Bearbeiten von Symbolen) dekoriert.

Ich struggeling jetzt bei der rekursiven Löschung, da ich ein IEnumerable (Children) verwende, das das umgekehrte Ergebnis von ParentNodeID ist. Beim Löschen eines Knotens wurden die untergeordneten Elemente aktualisiert, und das System gibt einen Aufzählungsfehler aus (die Sammlung wurde geändert). Ich hatte vor ein paar Jahren einen solchen Fehler, aber ich kann mich nicht erinnern, wie ich es repariert habe. Irgendein Rat?

So, hier ist das, was ich habe:

~/Modelle/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; } 
} 

~/Controller/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); 
} 

~/Ansichten/Bäume/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 &nbsp; <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>&nbsp; <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 &nbsp; <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>&nbsp; <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> 

Bearbeiten - Lösung:

public void DeleteRecursive(Tree tree) 
{ 
    foreach(var child in tree.Children.ToArray<Tree>()) 
    { 
     DeleteRecursive(child); 
    } 
    db.Trees.Remove(tree); 
} 

einen Array löschen aus nicht der ursprünglichen Sammlung nicht verändert.

Credits to Johnathon Sullinger: Delete item in nested collections of Nth level

+0

Die Sammlung wurde geändert? Verwenden Sie eine 'for'-Schleife anstelle einer' foreach'-Schleife in der 'DeleteRecursive'-Methode. –

+0

Ah, ich habe eine bessere Lösung, als mit einer For-Schleife (was irgendwie alt-skool imho ist). – SnakeByte

+0

Was ist Old-School über 'für'? Jetzt erstellen Sie ein Array, das Sie nicht benötigen. Wie auch immer, wenn Sie Ihr eigenes Problem lösen, ist es in Ordnung, eine Antwort auf Ihre eigene Frage zu schreiben und sie sogar rechtzeitig als akzeptiert zu markieren. –

Antwort

0
public void DeleteRecursive(Tree tree) 
{ 
    foreach(var child in tree.Children.ToArray<Tree>()) 
    { 
     DeleteRecursive(child); 
    } 
    db.Trees.Remove(tree); 
} 

mit einem Array aus nicht löschen nicht der ursprünglichen Sammlung ändern.