在 EF6 中同时删除本地子实体和 DB 子实体
Posted
技术标签:
【中文标题】在 EF6 中同时删除本地子实体和 DB 子实体【英文标题】:Deleting both local child entities and DB child entities in EF6 【发布时间】:2014-09-05 10:12:25 【问题描述】:使用 Entity Framework 6,我得到了主实体和细节实体。我有一个 WinForm,它在给定主实体的网格中显示详细数据。上下文在表单的整个生命周期中都保持不变。
详细列表通过 BindingList 绑定到网格:
detailBindingSource = new BindingSource();
detailBindingList = new BindingList<Detail>(master.Details);
detailBindingSource.DataSource = detailBindingList;
detailGrid.SetDataBinding(detailBindingSource, "");
当用户删除网格中的一行时,以下代码会删除详细信息(cmets 是我对代码所做的认为的解释):
var row = detailGrid.GetRow(); // Get the currently selected row in the detail grid
var detail = (Detail)row.DataRow; // Get the entity related to the row
row.Delete(); // This will delete the line from the list, but not from the DB
if (detail.ID > 0) // Don't try to delete a row that's only been added in memory and not to the DB
dbset.Remove(detail); // This will mark the entity to be deleted from the DB
当用户完成后,更改将被保存:
context.SaveChanges();
如果我删除现有行并保存,一切都会很好。如果我删除在表单/上下文的生命周期内添加的行并保存,一切都会很好。但是,如果我同时执行这两项操作——删除现有行并删除新添加且尚未保存的行——我会在保存时收到以下异常:
System.InvalidOperationException:操作失败:无法更改关系,因为一个或多个外键属性不可为空。当对关系进行更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。
搜索有关异常的信息时,我发现了一些关于如何从父实体的导航列表中删除不足以删除实体本身的参考,但我认为上面代码中对 Remove 的调用解决了 (如果我只删除现有的行,似乎是这样)。
有谁知道为什么只有在删除每种类型(新旧)的行时才会发生异常?
【问题讨论】:
我认为您收到此错误,因为您尝试删除 HAS NOT YET an ID 的新记录,因为未保存上下文。因此,您添加一条记录并尝试从仅存在于 DataGridView 中的实体中删除。 我从行中保存离开事件的任何新行,如果你想点击删除,你可以这样做:)并且将被删除,因为已经保存在上下文中;) 【参考方案1】:您要删除的现有行在所有三个测试中是否相同?我的意思是,它是具有相同基础数据、相同关系的同一行吗? 似乎在第三个测试中,您要删除的现有行与另一个表有关系,而另一个表本身与第三个表具有不可为空的关系。当关系消失时,第三个表上的相应行也需要删除。
【讨论】:
感谢您的建议,但它们是相同的行,并且子行与父行以外的任何内容均不相关。 在创建父行时是否创建了任何子行?如果是这样,请尝试在删除父行时显式删除关联的子行。【参考方案2】:如果您按照应有的方式创建和删除上下文,则不会有任何问题。不要使用全局上下文。
【讨论】:
【参考方案3】:这并不能解释为什么会发生错误(或者为什么在某些情况下不会发生),但解决方案是分离数据库中不存在的新添加的行:
if (detail.ID > 0)
dbset.Remove(detail);
else
dbset.Detach(detail);
【讨论】:
以上是关于在 EF6 中同时删除本地子实体和 DB 子实体的主要内容,如果未能解决你的问题,请参考以下文章