ASP.NET MVC 3一对多无法更新桥表

时间:2013-01-31 23:08:57

标签: asp.net-mvc-3 entity-framework ef-code-first one-to-many

我环顾了几个小时,但我似乎无法找到解决问题的直接方法。

基本上,我有一对多的关系,与桌子联系在一起。我的控制器似乎完美地处理'create'方法,在'1'表和桥接'many'表中创建记录。

但是,'edit'方法似乎根本不修改/更新桥接表。关于我做错了什么的想法,以及为什么它与'创造'方法不同?

为简洁起见,我想说我有以下型号:

public class Incident
{
    [Key]
    public int IncidentID { get; set; }
    public string Title { get; set; }
    public virtual ICollection<IncidentResources> Resources{ get; set; }
}

资源模型:

public class Resource
{
    [Key]
    public int ResourceID{ get; set; }
    public int Name { get; set; }
    ...OTHER FIELDS REMOVED FOR BREVITY...
}

我正在通过桥接表和模型来连接这两个:

public class IncidentResource
{
    [Key]
    public int IncidentResourceID { get; set; }
    public int IncidentID { get; set; }
    public int ResourceID { get; set; }
    public virtual <Resource> Resource { get; set; }
}

在我的控制器中,我有以下代码:

[HttpPost]
public ActionResult Create(Incident incident)
{
  //incident.Resources is returned as a valid object...
  if (ModelState.IsValid)
  {        
    db.Incidents.Add(incident);
    db.SaveChanges();
    return RedirectToAction("Index");
  }
  return View(incident);
}

以上作品完美无缺!正如我所提到的,新事件被插入到正确的表中,并且分配给事件的所有资源都被添加到IncidentResources表中。

但是,以下代码不适用于编辑...

[HttpPost]
public ActionResult Edit(Incident incident)
{
  if (ModelState.IsValid)
  {
    //THE USER CAN ADD ADDITIONAL RESOURCES
    foreach (IncidentResource r in incident.Resources)
    {
      r.IncidentID = incident.IncidentID;
    }
    db.Entry(incident).State = EntityState.Modified;
    db.SaveChanges();
    return RedirectToAction("Index");
  }
  return View(incident);
}

同样,上面似乎对IncidentResources表没有任何作用。不会添加,删除或更新记录。我也没有收到错误。它只是没有做任何事情。

请注意,我不想删除桥表数据并重新插入。我将与那些我不想孤儿的数据建立一对多的关系。

我不了解这是如何运作的?

6 个答案:

答案 0 :(得分:1)

您需要附加在EF外部创建的实体实例,并让EF知道它已被修改。

尝试添加:

db.Incidents.Attach(incident);
在改变状态之前

。在您的情况下,您的最后一段代码应如下所示:

[HttpPost]
public ActionResult Edit(Incident incident)
{
  if (ModelState.IsValid)
  {
    //THE USER CAN ADD ADDITIONAL RESOURCES
    foreach (IncidentResource r in incident.Resources)
    {
      r.IncidentID = incident.IncidentID;
    }
    db.Incidents.Attach(incident);
    db.Entry(incident).State = EntityState.Modified;
    db.SaveChanges();
    return RedirectToAction("Index");
  }
  return View(incident);
}

答案 1 :(得分:0)

似乎IncidentResource对象中的IncidentID未映射为Incident表的外键。尝试添加ForeignKey注释以将IncidentID显式设置为指向Incident:

的外键
   [ForeignKey("Incident")]
    public int IncidentID { get; set; }

答案 2 :(得分:0)

我想知道,在您当前的代码中,实体框架是否发现事件对象根本没有被更改,并且没有尝试查看是否有需要调整的IncidentResources。

尝试在循环中添加以下行:

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

编辑:我应该补充一点,在写完这个答案之后,我正在观看Julie Lerman关于实体框架的演讲,其中她确实提到“修改后的状态不会通过图形级联”,这意味着上面的代码应该为你做。

答案 3 :(得分:0)

除非您在表单中的隐藏字段中跟踪IncidentID,否则我打赌问题源于它尝试更新不存在的事件(IncidentID:0)

这将取决于您的路线,但假设默认路线模式:

[HttpPost]
public ActionResult Edit(int id, Incident incident)
{
  incident.IncidentID = id;

  if (ModelState.IsValid)
  {
    //THE USER CAN ADD ADDITIONAL RESOURCES
    foreach (IncidentResource r in incident.Resources)
    {
      r.IncidentID = incident.IncidentID;
    }
    db.Entry(incident).State = EntityState.Modified;
    db.SaveChanges();
    return RedirectToAction("Index");
  }
  return View(incident);
}

答案 4 :(得分:0)

如果可以,您可以尝试将IncidentResource表的外键IncidentID添加到主键以生成复合主键。我遇到了类似的问题,这对我有帮助。

我从其他一些stackoverflow问题中得到了解决方案。我的设置与这些完全不匹配,因为我使用AutoMapper和Entity模型的第一个工作单元方法,但是在关系表上使用复合键修复了我的问题。

Is it possible to remove child from collection and resolve issues on SaveChanges?

What's the difference between identifying and non-identifying relationships?

答案 5 :(得分:0)

你不应该做以下

[HttpPost]
public ActionResult Edit(Incident incident)
{
  if (ModelState.IsValid)
  {
    //THE USER CAN ADD ADDITIONAL RESOURCES
    foreach (IncidentResource r in incident.Resources)
    {
      r.IncidentID = incident.IncidentID;
      db.Entry(r).State = EntityState.Modified;
    }
    db.SaveChanges();
    return RedirectToAction("Index");
  }
  return View(incident);
}