I followed this Saving Many to Many relationship data on MVC Create view
This works for adding my many to many values.
But when I try to edit using the same code, No matter what I do, it doesn't change the many to many values.
My scenario is...
I have Menus, and Pages.
Many pages can be added to many menus.
I add the pages to the menu in question perfectly, but when editing, it results in the same values every time, even if I call Menu.Pages.Clear(); Context.SaveChanges(); It just results in the same values as before the edit on the page list associated to the menu.
[HttpPost]
public ActionResult Edit(MenuViewModel MenuViewModel, int PageID, int ActivePosition, int OldAP)
{
Service.AddOrUpdateCourses(MenuViewModel.ZMenu, MenuViewModel.Pages);
ViewBag.Message = Service.CreateOrUpdate<ZMenu>(MenuViewModel.ZMenu, PageID, ActivePosition, OldAP);
if (ViewBag.Message.ToString() == "true")
{
Service.Commit();
return RedirectToAction("Index");
}
ViewBag.ActivePosition = ModuleManager.AvailableModulePositions(OldAP);
ViewBag.PageID = Service.GetPageSelectList(MenuViewModel.ZMenu.Page.ID);
return View(MenuViewModel);
}
PageID is the page the module (menu) is positioned onto, ActivePosition is the module position it is in, OldAP is the position it WAS in before the update. Things are pre-fixed with 'Z' because it's the general theme in the code and stops any confusion with any other functions.
Service is the Repository.
public void AddOrUpdateCourses(ZMenu ZMenu, IEnumerable<AssignedPageData> AssignedPages)
{
ZMenu.Pages.Clear();
foreach (var AssignedPage in AssignedPages)
{
if (AssignedPage.Assigned)
{
var newpage = Context.ZPages.Find(AssignedPage.ID);
Context.ZPages.Attach(newpage);
ZMenu.Pages.Add(newpage);
}
}
}
Potentially useless information... The other method used....
public string CreateOrUpdate<T>(object _Module, int PageID, int ActivePosition, int OldAP = -1)
{
Type type = typeof(T);
dynamic Module = type.DynamicCast(_Module);
// set the date, depending on if its a create or edit
if (Module.ID == 0 || Module.ID == null)
Module.Date = DateTime.Now;
else
{
int ID = Module.ID;
Module.Date = Context.ZModules.AsNoTracking().Single(x => x.ID == ID).Date;
}
Module.Type = Context.ZModuleTypes.Single(x => x.Name == type.Name.Substring(1, type.Name.Length - 1));
Module.Page = Context.ZPages.Single(x => x.ID == PageID);
Module.ActivePosition = ActivePosition;
bool PositionTaken = false;//this.CheckModulePositions<T>(_Module, OldAP);
if (PositionTaken)
{
return "Position " + Module.ActivePosition + " is taken, please select another";
}
else
{
try
{
int ID = Module.ID ?? -1;
if (Context.ZModules.AsNoTracking().Where(x => x.ID == ID).Count() == 0)
{
Context.Entry(Module).State = System.Data.EntityState.Added;
}
else
{
Context.Entry(Module).State = System.Data.EntityState.Modified;
}
return "true";
}
catch (Exception ex)
{
return ex.Message;
}
}
}
I have disabled the module position protection (1 module per module position) to stop that from being a potential problem, and that hadn't fixed it, just incase you were wondering why I have a small line of code commented out above.
I have debugged this, and the ZMenu entity has the correct Pages in question as the Commit() method is called, but after that the page list gets reverted to how it was before the edit. Works when creating.
Any one have any clue ?
Will supply more information if needed.
EDIT:
Here is the ViewModel in question...
public class MenuViewModel
{
public ZMenu ZMenu { get; set; }
public virtual ICollection<AssignedPageData> Pages { get; set; }
public MenuViewModel(ZMenu ZMenu)
{
this.ZMenu = ZMenu;
}
public MenuViewModel()
{
}
}
EDIT 2:
Due to the comment below, and some continued work, the code is now as follows, in what seems to be the problem area, I have now encountered an error, but I am in the dark on how I would fix the error.
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
public void AddOrUpdateCourses(ZMenu ZMenu, IEnumerable<AssignedPageData> AssignedPages)
{
Context.ZMenuModules.Attach(ZMenu);
HashSet<int> CurrentPages = new HashSet<int>
(ZMenu.Pages.Select(i => i.ID));
foreach (var AssignedPage in AssignedPages)
{
ZPage newpage = Context.ZPages.Find(AssignedPage.ID);
Context.ZPages.Attach(newpage);
if (AssignedPage.Assigned)
{
if (!CurrentPages.Contains(AssignedPage.ID))
{
ZMenu.Pages.Add(newpage);
}
}
else
{
if (CurrentPages.Contains(AssignedPage.ID))
{
ZMenu.Pages.Remove(newpage);
}
}
}
}
The error happens when the Context.SaveChanges() is called.
EDIT 3:
As you can see this is partially answered now.
Can anyone tell me how I would refresh the ZMenu.Pages value without causing a multiple objects being tracked error.