问题
You can see my database diagram on my previous post: MVC EF - Update navigation property
I want to delete and insert categories for one post. I get the error Collection was modified; enumeration operation may not execute. at the row
foreach (PostMapping pm in current_list_category)
This is my function:
//
// 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);
}
Is there another approach?
I don't get anymore the error but now I have another problem.
Before updating I have this in database:
PostID CategoryID
1 1
1 2
1 3
, but after I update(I want to remove categories with ids 1,2,3 and add category with id 4)
PostID CategoryID
1 NULL
1 NULL
1 NULL
1 4
Why?
I tried another approach but with no succes:
.....
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);
.....
instead:
....
post.PostMappings.Remove(pm);
Category category = db.Categories.Where(c => c.ID == categoryId).SingleOrDefault();
category.PostMappings.Remove(pm);
.....
But I get the error:AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges.
回答1:
You can't change collection while you enumerating it so you need temporary collection and enumerate over it. something like this:
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);
}
}
}
Or even better especially if you have just few items for remove, you can collect removed items in separate list and then enumerate over that list and remove item from source list
Made changes according to post edit:
you also need to mark your removed entries state as EntityState.Deleted
回答2:
Finally I have the answer.
I hope this will help someone.
//
// 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);
}
来源:https://stackoverflow.com/questions/22477871/update-navigation-properties-in-asp-net-mvc