我有一个使用EF6 Code First的MVC 5项目。它包括包含复杂子对象列表的模型。我需要能够在父对象的“编辑”页面上添加,更新和删除子对象,同时保存对父对象的更改。
我在控制器中如何处理这些操作时陷入了两难境地。这是相关的代码。
型号:
public class Parent
{
public int Id {get;set;}
//other properties
public virtual IList<Child> Children {get;set;}
}
public class Child
{
public int Id {get;set;}
//other properties
public int Parent_Id {get;set;}
[ForeignKey("Parent_Id")]
public virtual Parent Parent {get;set;}
[NotMapped]
public bool toBeDeleted {get;set;}
}
控制器:
[HttpPost]
public ActionResult Edit([Bind(Include = "Id, Children")] Parent p)
{
...
//For some reason children are brought in with Parent_Id = null.
//Manually resetting it fixes this issue.
//Needs to be set before parent = modified for referential integrity
foreach(var c in p.Children)
{
c.Parent_Id = p.Id;
}
context.Entry(p).State = EntityState.Modified;
for(int i = 0; i < p.Children.Count; i++)
{
if(p.c[i].toBeDeleted)
{
Child childToDelete = context.Children.Find(p.c[i].Id);
context.Entry(childToDelete).State = EntityState.Deleted;
i--;
}
else
{
context.Entry(p.c[i]).State = p.c[i].Id > 0 ? EntityState.Modified : EntityState.Added;
}
}
context.SaveChanges();
...
}
我必须在删除后包含“i--”,因为父项已设置为已修改,所有标记为删除的子对象都会立即从列表中删除,这会导致循环关闭。 (我最初有一个foreach循环,但是这个问题在循环中间集合大小改变时导致错误)
虽然我的工作方式,但感觉就像拼凑修补一样。在我看来,应该有一个更好的方法来实现它,而不是在每次删除后手动减少for循环中的迭代器,以保持项目正确排列。有一个更好的方法吗?有没有办法分别设置每个对象的实体状态而不影响相关对象的状态?
答案 0 :(得分:1)
怎么样:
p.Children.Where(m => m.toBeDeleted).ToList().ForEach(m => p.Children.Remove(m));
只需从集合中删除子项,Entity Framework就会将它们标记为删除。
此外,对于您的添加条件,如果您为Parent_Id
添加了一个隐藏字段(如果没有,则应该添加),那么孩子们将设置Parent_Id
,除非他们'重新开始。如果它们是新的,那么仅仅因为Children
Parent
的{{1}}集合,它们将被添加,并且实体框架将自动设置Parent_Id
属性。最有可能的是,您的问题在于尝试保存已存在Parent_Id
属性的现有子项,因为它未发布。这将导致完整性错误,因为它查看实体框架,就好像您想要将Parent_Id
更改为null。