使用DbContext API添加和删除多对多

时间:2012-05-28 10:22:44

标签: c# asp.net .net entity-framework-4 dbcontext

我正在使用Entity Framework和DbContext API来构建我的应用程序,但是我在处理具有多对多关系的对象时遇到了问题。简化的保存方法可能如下所示

public void MyObj_Save(MyObj myobj)
{
  DbContext.Entry(myobj).State = EntityState.Added;
  DbContext.SaveChanges();
}

此代码工作正常,但如果MyObj包含多对多关系,则不会保存。我知道从使用旧的POCO API,我需要将相关的对象附加到上下文,但我找不到使用DbContext API正确执行此操作的方法 - 下面的简化示例

public void MyObj_Save(MyObj myobj, List<OtherObj> otherObjList)
{
  foreach (OtherObj otherObj in otherObjList)
  {
    DbContext.OtherObj.Attach(otherObj);
    myobj.OtherObj.Add(otherObj);
  }

  DbContext.Entry(myobj).State = EntityState.Added;
  DbContext.SaveChanges();
}

我没有得到错误,但关系没有保存。怎么办?

2 个答案:

答案 0 :(得分:3)

我引用你的(重要的!)评论:

  

我发送给方法的对象是附加,EntityState是   不变即可。我的DbContext的配置是,已禁用   AutoDetectChangesEnabled ...

所以,你的代码看起来像这样:

DbContext.Configuration.AutoDetectChangesEnabled = false;

DbContext.Entry(myobj).State = EntityState.Unchanged;
foreach (OtherObj otherObj in otherObjList)
    DbContext.Entry(otherObj).State = EntityState.Unchanged;

// entering MyObj_Save method here
foreach (OtherObj otherObj in otherObjList)
{
    //DbContext.OtherObj.Attach(otherObj); // does not have an effect
    myobj.OtherObj.Add(otherObj);
}

DbContext.Entry(myobj).State = EntityState.Added;
DbContext.SaveChanges();

这确实不起作用,因为EF没有注意到您已更改myobj与行OtherObjmyobj.OtherObj.Add(otherObj);列表之间的关系,因为您已禁用自动改变检测。因此,不会将任何条目写入连接表。只保存myobj本身。

您无法在实体上设置任何状态以将状态管理器置于保存关系的状态,因为它不是一个实体状态,这在这里很重要,但是关系状态。这些是对象状态管理器中的单独条目,由变更检测创建和维护。

我看到三个解决方案:

  • 设置DbContext.Configuration.AutoDetectChangesEnabled = true;

  • 手动调用DetectChanges

    //...
    DbContext.Entry(myobj).State = EntityState.Added;
    DbContext.ChangeTracker.DetectChanges();
    DbContext.SaveChanges();
    
  • 在将新myobj设置为Added状态之前从上下文中删除它(这对我来说非常讨厌):

    // entering MyObj_Save method here
    DbContext.Entry(myobj).State = EntityState.Detached;
    foreach (OtherObj otherObj in otherObjList)
    //...
    

也许有可能 - 通过ObjectContext到达IObjectContextAdapter - 手动修改对象状态管理器中的关系条目,但我不知道如何。

在我看来,手动操作实体(和关系)状态的这个过程并不是你应该使用EF的方式。引入AutoDetectChangesEnabled是为了使EF更容易和更安全,并且唯一建议的禁用它的情况是高性能要求(例如批量插入)。如果您在不需要的情况下禁用自动更改检测,则会遇到难以检测的类似问题,并且需要EF内部工作的高级知识来修复这些错误。

答案 1 :(得分:2)

public void MyObj_Save(MyObj myobj, List<OtherObj> otherObjList)
{
    DbContext.Entry(myobj).State = EntityState.Added;

    foreach (OtherObj otherObj in otherObjList)
    {
        (((System.Data.Entity.Infrastructure.IObjectContextAdapter)DbContext)
            .ObjectContext)
            .ObjectStateManager
            .ChangeRelationshipState(myobj, otherObj,
                q => q.OtherObjs, EntityState.Added);
    }

    DbContext.SaveChanges();
}

同样,这是一个简化而非现实的例子!