EF Code First多对多更新(MVC 4)

时间:2012-08-30 12:18:58

标签: asp.net-mvc entity-framework asp.net-mvc-4

我跟着这个 Saving Many to Many relationship data on MVC Create view

这适用于添加我的多个值。

但是当我尝试使用相同的代码进行编辑时,无论我做什么,它都不会改变多对多的值。

我的情景是......

我有菜单和页面。

许多页面都可以添加到许多菜单中。

我将页面完美地添加到相关菜单中,但是在编辑时,每次都会产生相同的值,即使我调用了Menu.Pages.Clear(); Context.SaveChanges();它只会产生与菜单关联的页面列表上的编辑之前相同的值。

[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是模块(菜单)所在的页面,ActivePosition是它所处的模块位置,OldAP是更新前它所处的位置。 事物是用'Z'预先修复的,因为它是代码中的一般主题,并且可以阻止任何其他功能的混淆。

服务是存储库。

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);
            }
        }
    }

潜在无用的信息......使用的另一种方法......

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;
            }
        }
    }

我已经禁用了模块位置保护(每个模块位置1个模块)以阻止它成为一个潜在的问题,并且没有修复它,只是因为你想知道我为什么要在上面注释掉一小段代码

我调试了这个,并且在调用Commit()方法时,ZMenu实体具有正确的页面,但之后页面列表将恢复到编辑之前的状态。在创建时起作用。

任何人都有任何线索吗?

如果需要,将提供更多信息。

编辑:

这是有问题的ViewModel ......

public class MenuViewModel
{
    public ZMenu ZMenu { get; set; }
    public virtual ICollection<AssignedPageData> Pages { get; set; }

    public MenuViewModel(ZMenu ZMenu)
    {
        this.ZMenu = ZMenu;
    }

    public MenuViewModel()
    {

    }
}

编辑2:

由于下面的评论和一些继续工作,代码现在如下,在什么似乎是问题区域,我现在遇到了一个错误,但我在黑暗中如何修复错误

  

存储更新,插入或删除语句会影响意外的行数(0)。自实体加载后,实体可能已被修改或删除。刷新ObjectStateManager条目。

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);
                }
            }
        }
    }

调用Context.SaveChanges()时会发生错误。

编辑3:

正如您所看到的,现在已部分回答。

任何人都可以告诉我如何刷新ZMenu.Pages值而不会导致多个对象被跟踪错误。

3 个答案:

答案 0 :(得分:0)

发现问题。

调试后,我注意到有问题的ZMenu根本没有页面中的页面,即使它有一个,即使编辑不起作用。所以这是错的。 (在编辑之前)。

所以我使用传递给HttpPost编辑操作的Model的ID来从Context中“找到”ZMenu并使用它,而不是我以前的“ViewModel.ZMenu”。

这使得ZMenu有它应该具有的1页,这必须解决程序中的任何问题并使编辑成功,我很高兴,因为这已经困扰了我多年。

答案 1 :(得分:0)

最终通过遵循Microsoft教程修复它。

我建议任何查看问题顶部链接的人如果遇到问题,请遵循此规则,因为情况相同。

http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/updating-related-data-with-the-entity-framework-in-an-asp-net-mvc-application

(最底部的截图是我试图做的)

答案 2 :(得分:0)

我写了一些博文,详细介绍了如何使用EF Code First在多对多场景中创建/更新/删除记录。还有一个完整的解决方案附在帖子上,所以希望你或其他人阅读这篇文章会发现它很有用。这是第三部分也是最后一部分:

Saving many to many data in MVC4