在EF6中删除本地子实体和DB子实体

时间:2014-07-15 09:22:17

标签: c# winforms entity-framework entity-framework-6 master-detail

使用Entity Framework 6,我有主要和详细的实体。我有一个WinForm,它在给定主实体的网格中显示详细数据。上下文在表格的整个生命周期中都有。

详细信息列表使用BindingList绑定到网格:

detailBindingSource = new BindingSource();
detailBindingList = new BindingList<Detail>(master.Details);
detailBindingSource.DataSource = detailBindingList;
detailGrid.SetDataBinding(detailBindingSource, "");

当用户删除网格中的一行时,以下代码会删除详细信息(这些注释是我对代码所做的思考的解释):

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的调用解决了这个问题(似乎我只删除现有的行。)

有没有人知道为什么只有在删除每种类型(新旧)的行时才会发生异常?

3 个答案:

答案 0 :(得分:0)

在所有三个测试中,您要删除的现有行是否相同?我的意思是,它是否具有相同的基础数据,相同的关系? 似乎在第三次测试中,您要删除的现有行与另一个表有关系,该表本身与第三个表具有不可为空的关系。当关系消失时,第三个表上的相应行也需要删除。

答案 1 :(得分:0)

如果您创建并删除了上下文,则应该没有问题。不要使用全局上下文。

答案 2 :(得分:0)

这不能解决错误发生的原因(或者为什么在某些情况下不会发生错误),但解决方案是分离新添加的不在数据库中的行:

if (detail.ID > 0)
    dbset.Remove(detail);
else
    dbset.Detach(detail);