4

I've looked around for hours, but I can't seem to find a straight forward method for solving my problem.

Basically, I have a 1-to-many relationship, bridged with a table. My controller seems to handle the 'create' method perfectly, creating records within the '1' table and the bridging 'many' table.

However, the 'edit' method doesn't seem to modify/update the bridging table at all. Any thoughts on what I'm doing wrong, and why it differs from the 'create' approach?

For brevity, let's say I have the following model:

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

And an Resource model:

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

And I am bridging these two via a bridging table and model:

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

In my Controllers, I have the following code:

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

The above works perfectly! As I mentioned, the new Incident is inserted into the proper table, and all Resources assigned to the incident are added to the IncidentResources table.

However, the following code DOES NOT work this way for the edit...

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

Again, the above seemingly does nothing to the IncidentResources table. Records are not added, removed, or updated. I don't receive an error either. It just doesn't do anything.

Please note that I DO NOT want to just trash the bridge table data and reinsert. I will have 1-to-many relationships to that data that I do not want to orphan.

What am I not understanding about how this works?

4

6 回答 6

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);
}
于 2013-01-31T23:18:29.177 回答
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);
}
于 2013-02-06T08:28:19.413 回答
0

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

   [ForeignKey("Incident")]
    public int IncidentID { get; set; }
于 2013-02-01T01:35:15.227 回答
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);
}
于 2013-02-08T09:04:24.390 回答
0

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

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

是否可以从集合中删除子项并解决 SaveChanges 上的问题?

识别关系和非识别关系有什么区别?

于 2013-02-07T17:22:02.317 回答
0

我想知道,在您当前的代码中,Entity Framework 是否看到 Incident 对象根本没有更改,并且没有尝试查看是否有 IncidentResources 需要调整。

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

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

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

于 2013-02-05T20:39:36.927 回答