如何更新关系数据库TABLES?

时间:2012-10-29 06:21:02

标签: c# database entity-framework

我正在使用Entity Framework 4.0。我在更新数据库中的数据时遇到问题。我得到了这个例外:

  

ObjectStateManager中已存在具有相同键的对象。
   ObjectStateManager无法使用相同的键跟踪多个对象。

我正在研究关系数据库。以下是3个实体和那里的关系:

         1    to   *        1   to    *
Ceremony -----------> Menu ------------> CourseOption

如果我更新已包含MenusCourseOptions的仪式,一切正常。当我们在更新时在仪式中插入新的MenuCourseOption条目时,问题就出现了。比我上面提到的例外。

更新现有仪式的C#代码

public HttpResponseMessage PutCeremony(int id, Ceremony ceremony)
{
    if (ModelState.IsValid && id == ceremony.Id)
    {
       db.Entry(ceremony).State = EntityState.Modified;

       try
       {
           db.SaveChanges();
       }
       catch (DbUpdateConcurrencyException)
       {
           return Request.CreateResponse(HttpStatusCode.NotFound);
       }

       return Request.CreateResponse(HttpStatusCode.OK, ceremony);
    }
    else
    {
       return Request.CreateResponse(HttpStatusCode.BadRequest);
    }
}

如何摆脱这个问题?请帮忙

修改

今天我花了一整天的时间,我读了很多关于articals和stackoverflow的问题。我找到once a product is fetched from the Context, the context is keeping track of it所以为什么而不是使用:

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

我用过

db.Entry(db.Ceremonies.Find(ceremony.Id)).CurrentValues.SetValues(ceremony);

现在,通过这样做,更改了异常,并且Ceremony实体属性正在正确更改。但是关于Menus条目和CourseOptions条目的仪式没有更新。请给我建议的人。我是EF的新手。

1 个答案:

答案 0 :(得分:1)

更新分离的对象图可能非常困难。 (这里只有一个子集合的例子:https://stackoverflow.com/a/5540956/270591如果你有一个盛大的子集合,那就更复杂了。)

没有通用的方法或简单的方法,比如将状态设置为Modified(它只将标量属性标记为已更改),并希望它存储所有对象图更改。

要考虑实施此类更新的详细信息:

  • 当菜单添加到仪式中时,用户创建新菜单,还是仅在仪式与现有菜单之间建立关系?
  • 当菜单从仪式中删除时,用户删除现有菜单,或者他只发布仪式和菜单之间的关系,但菜单应该仍然存在于数据库中(那么FK必须是可以为空的吗?
  • 用户可以在视图中更改(标量)菜单属性,还是只能将菜单添加到仪式中或删除它们而不更改菜单本身?
  • 同样的问题适用于每个CourseOptions的孙子集合Menu

对于(相对简单)用户在您的特定仪式编辑视图...

  • 可以修改仪式的标量属性
  • 可以删除现有菜单,这些菜单应该在删除时从数据库中删除,并且还应删除相关的CourseOptions,并在数据库中启用该关系的级联删除
  • 可以为应该插入数据库的仪式创建和添加新菜单
  • 无法更改现有菜单的标量属性
  • 无法将CourseOptions添加到现有Menu,也无法从Menu
  • 中删除它们
  • 可以将新CourseOptions添加到新的Menu(并且CourseOptions应与新菜单一起插入)
  • 无法更改现有CourseOption
  • 的标量属性

......代码看起来像这样:

var ceremonyInDb = db.Ceremonies.Include(c => c.Menus)
    .Single(c => c.Id == ceremony.Id);

db.Entry(ceremonyInDb).CurrentValues.SetValues(ceremony);

foreach (var menuInDb in ceremonyInDb.Menus.ToList())
    if (!ceremony.Menus.Any(m => m.Id == menuInDb.Id))
        db.Menus.Remove(menuInDb);

foreach (var menu in ceremony.Menus)
    if (!ceremonyInDb.Menus.Any(m => m.Id == menu.Id))
        ceremonyInDb.Menus.Add(menu);

db.SaveChanges();

如果某些限制不适用(即用户可以在您的视图中进行更复杂的修改),则代码将更加复杂。但基本思想是从数据库中加载对象图(带有Include的根和子项以及可能带有Include(...Select(...))的子项),将原始图与新的分离图进行比较并对原始图应用更改根据与新图表的差异绘制图表。