1

階層的なデータで遊んで子供を持つノードを削除しようとすると、何か問題が発生しました。MVC 5 Entity Framework 6 - ネストされた/階層的なデータを削除する

私はthis articleに似たサンプルツリーを設定し、ちょっとしたブートストラップ(アイコンの追加、削除、編集)でul-liアイテムを装飾しました。

私はIEnumerable(子)を使用しているので、再帰的削除時に苦労しています。これはparentNodeIDの逆の結果です。そのため、ノードを削除すると、子ノードが更新され、列挙エラー(コレクションが変更された)がスローされます。私は数年前にこのようなエラーを抱えていましたが、私はそれをどのように修正したのか覚えていません。何かアドバイス?だからここ

は、私が得たものである:

〜/モデル/ 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; } 
} 

〜/コントローラ/ 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 &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> 

編集 - ソリューション:

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

元のコレクションは変更されませんから削除するように配列を使用しました。元のコレクションを変更しませんから削除する配列を使用して

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

+0

コレクションが変更されましたか? 'DeleteRecursive'メソッドで' foreach'ループの代わりに 'for'ループを使ってみてください。 –

+0

ああ、私はより良い解決策を持っていますforループを使用して(これはちょっと古いskho imhoです)。 – SnakeByte

+0

'のための古い学校は何ですか?これで、必要のない配列を作成できます。とにかく、あなた自身の問題を解決するならば、自分の質問への答えを書いて、それを正当な時に受け入れたものとしてマークすることも大丈夫です。 –

答えて

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

関連する問題