更新ASP.NET MVC中的导航属性

时间:2014-03-18 11:23:19

标签: c# asp.net-mvc entity-framework updatemodel

您可以在我之前的帖子中看到我的数据库图表:MVC EF - Update navigation property

我想删除并插入一个帖子的类别。 我收到错误收集被修改;枚举操作可能无法执行。在行

foreach (PostMapping pm in current_list_category)

这是我的功能:

//
// POST: /BlogPost/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Post post, int[] selectedCategories)
{
   if (ModelState.IsValid)
   {
     List<PostMapping> current_list_category = db.PostMappings.Where(p => p.PostID == post.ID).ToList();
     post.PostMappings = current_list_category;      
     foreach (PostMapping pm in current_list_category)
     {
        int categoryId = pm.CategoryID.Value;
        if (selectedCategories != null)
        {
           if (selectedCategories.Contains(categoryId))
           {
              selectedCategories = selectedCategories.Where(val => val != categoryId).ToArray();
           }
           else
           {
              post.PostMappings.Remove(pm);
              Category category = db.Categories.Where(c => c.ID == categoryId).SingleOrDefault();
              category.PostMappings.Remove(pm);
           }
        }                  
     }
     foreach (var id in selectedCategories)
     {
        Category category = db.Categories.Where(c => c.ID == id).SingleOrDefault();
        PostMapping postMap = new PostMapping();
        postMap.Category = category;
        postMap.Post = post;
        postMap.ID = Guid.NewGuid();
        post.PostMappings.Add(postMap);
        category.PostMappings.Add(postMap);
     }
     db.Entry(post).State = EntityState.Modified;       
     db.SaveChanges();
     return RedirectToAction("Index");
   }
   return View(post);
}

还有其他方法吗?


我不会再得到错误,但现在我还有另一个问题。

在更新之前,我在数据库中有这个:

PostID CategoryID
1 1
1 2
1 3

,但在我更新后(我想删除带有ID 1,2,3的类别并添加ID为4的类别)

PostID CategoryID
1 NULL
1 NULL
1 NULL
1 4

为什么?

我尝试了另一种方法但没有成功:

.....
Post post2 = db.Posts.Where(p => p.ID == post.ID).SingleOrDefault();
post2.PostMappings.Remove(pm);
Category category = db.Categories.Where(c => c.ID == categoryId).SingleOrDefault();
category.PostMappings.Remove(pm);
 .....

代替:

....
post.PostMappings.Remove(pm);
Category category = db.Categories.Where(c => c.ID == categoryId).SingleOrDefault();
category.PostMappings.Remove(pm);
.....

但是我收到错误: AcceptChanges无法继续,因为对象的键值与ObjectStateManager中的另一个对象冲突。在调用AcceptChanges之前,请确保键值是唯一的。

2 个答案:

答案 0 :(得分:3)

枚举时无法更改集合 所以你需要临时收集并枚举它。 像这样的东西:

post.PostMappings = current_list_category;

List<PostMapping> temp = new List<PostMapping>();
temp.AddRange(current_list_category);

foreach (PostMapping pm in temp)
        {
            int categoryId = pm.CategoryID.Value;
            if (selectedCategories != null)
            {
                if (selectedCategories.Contains(categoryId))
                {
                    selectedCategories = selectedCategories.Where(val => val != categoryId).ToArray();
                }
                else
                {

                    post.PostMappings.Remove(pm);
                    Category category = db.Categories.Where(c => c.ID == categoryId).SingleOrDefault();
                    category.PostMappings.Remove(pm);
                }
            }

        }

甚至更好,特别是如果您只有少量要移除的项目,您可以在单独的列表中收集已删除的项目,然后枚举该列表并从源列表中删除项目

根据帖子编辑进行更改:

您还需要将已删除的条目标记为EntityState.Deleted

答案 1 :(得分:1)

最后我有答案。

我希望这会对某人有所帮助。

        //
    // POST: /BlogPost/Edit/5

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(Post post, int[] selectedCategories)
    {

        if (ModelState.IsValid)
        {
            List<PostMapping> current_list_category = db.PostMappings.Where(p => p.PostID == post.ID).ToList();


            List<PostMapping> temp = new List<PostMapping>();
            temp.AddRange(current_list_category);

            if (selectedCategories != null)
            {
                foreach (PostMapping pm in temp)
                {
                    int categoryId = pm.CategoryID.Value;

                    if (selectedCategories.Contains(categoryId))
                    {
                        selectedCategories = selectedCategories.Where(val => val != categoryId).ToArray();
                    }
                    else
                    {

                        post.PostMappings.Remove(pm);

                        db.Entry(pm).State = EntityState.Deleted;

                    }


                }
            }
            else
            {
                foreach (PostMapping pm in temp)
                {
                    int categoryId = pm.CategoryID.Value;

                    post.PostMappings.Remove(pm);

                    db.Entry(pm).State = EntityState.Deleted;
                }
            }


            if (selectedCategories != null)
            {
                foreach (var id in selectedCategories)
                {
                    Category category = db.Categories.Where(c => c.ID == id).SingleOrDefault();
                    PostMapping postMap = new PostMapping();
                    postMap.Category = category;
                    postMap.Post = post;
                    postMap.ID = Guid.NewGuid();

                    post.PostMappings.Add(postMap);

                    category.PostMappings.Add(postMap);
                }
            }

            db.Entry(post).State = EntityState.Modified;

            db.SaveChanges();

            return RedirectToAction("Index");
        }

        return View(post);
    }