使用Entity Framework同时更新和添加子行

我在修改和同时添加子行时遇到了一些麻烦。 我正在使用答案中的技术: stackoverflow.com/questions/5557829 / ….

问题出现在以下代码中:

public void EditReport(tbl_inspection inspection) { foreach (var roll in inspection.tbl_inspection_roll) { container.tbl_inspection_roll.Attach(roll); container.ObjectStateManager.ChangeObjectState(roll, (roll.id_inspection_roll == 0) ? EntityState.Added : EntityState.Modified); } container.SaveChanges(); } 

我总是至少有一行要更新。 当我有1行要添加时,它工作正常,问题是当我尝试同时添加多行时,显示众所周知的错误:

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

感觉就像我在这里遗漏了一些东西……

我认为你需要将修改后的内容拆分掉。 在您链接到Ladislav的问题中,以下代码为例:

 if (myEntity.Id != 0) { context.MyEntities.Attach(myEntity); context.ObjectStateManager.ChangeObjectState(myEntity, EntityState.Modified); } else { context.MyEntities.AddObject(myEntity); } context.SaveChanges(); 

我认为特别使用Attach,而不是使用AddObject是导致错误的原因。

编辑:尝试以下连接部分:

 var r = new tbl_inspection_roll { id_inspection_roll = roll.id_inspection_roll }; container.tbl_inspection_roll.Attach(r); container.Entry(r).CurrentValues.SetValues(roll); 

这里的问题是因为两个或多个子存根具有相同的键:0。一旦尝试连接第一个对象,它就会触发错误。

必须使用某种DTO重新设计该方法(我认为将ViewModel对象传递给域模型层是不正确的,这就是我使用存根的原因)。 或者调用一个函数来直接从Controller添加/修改。

编辑:

这是代码:

 public void EditReport(Inspection obj) { var inspection = new tbl_inspection { id_inspection = obj.ID, code = obj.Code }; foreach (var roll in obj.Rolls) { var rollStub = new tbl_inspection_roll { id_inspection_roll = roll.ID, id_inspection = obj.ID, description = roll.Description }; container.tbl_inspection_roll.Attach(roll); container.ObjectStateManager.ChangeObjectState(roll, (roll.id_inspection_roll == 0) ? EntityState.Added : EntityState.Modified); } container.tbl_inspection.Attach(inspection); container.ObjectStateManager.ChangeObjectState(inspection, EntityState.Modified); container.SaveChanges(); } 

欢迎任何更好的解决方案……

如果我正确理解您的问题,那么您正在尝试保存包含ParentObject和相关ChildObjects的对象图,并且您将获得exception,因为Attach()无法协调数据库中的ChildObjects和附加的ParentObject之间的Id冲突。

以下是我过去使用的一项工作。 它并不漂亮,但它完成了工作。

 public ParentObject Upsert(ParentObject newParentObject) { // Check for an existing ParentObject. ParentObject exisitingParentObject = container.ParentObjects.SingleOrDefault(o => o.Id == newParentObject.Id); // If not an existing ParentObject if (exisitingParentObject == null) { // Add a new ParentObject exisitingParentObject = container.ParentObjects.Add(container.ParentObjects.Create()); } // Update the properties of the existing ParentObject with the values of the new ParentObject var parentEntry = container.Entry(exisitingParentObject); parentEntry.CurrentValues.SetValues(newParentObject); // Remove ChildObjects that are in the existing but not in the new. for (int i = exisitingParentObject.ChildObjects.Count() - 1; i >= 0; i--) { ChildObject exisitingChildObject = exisitingParentObject.ChildObjects[i]; if (!newParentObject.ChildObjects.Any(o => o.Id == exisitingChildObject.Id)) { container.ChildObjects.Remove(exisitingChildObject); } } // Upsert new ChildObjects foreach (ChildObject newChildObject in newParentObject.ChildObjects) { // Check for an existing ChildObject ChildObject exisitingChildObject = exisitingParentObject.SingleOrDefault(o => o.Id == newChildObject.Id); // If not an existing ChildObject if (exisitingChildObject == null) { // Add a new ChildObject exisitingChildObject = exisitingParentObject.ChildObjects.Add(container.ChildObject.Create()); } var childEntry = container.Entry(exisitingChildObject); childEntry.CurrentValues.SetValues(newChildObject); } container.SaveChanges(); return exisitingParentObject; }