我正在使用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();
}
我没有得到错误,但关系没有保存。怎么办?
答案 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
与行OtherObj
中myobj.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();
}
同样,这是一个简化而非现实的例子!