C# Delete语句与引用约束冲突

C# Delete语句与引用约束冲突,c#,entity-framework,C#,Entity Framework,我想这有一个非常简单的答案。我是实体框架的新手,我正在创建一个测试应用程序,它由联系人和组作为对象/实体组成 以下是我删除组的代码: private void button_DeleteGroup_Click(object sender, EventArgs e) { var _selectedGroup = dataGridView_Groups.SelectedRows[0].DataBoundItem as Group; try

我想这有一个非常简单的答案。我是实体框架的新手,我正在创建一个测试应用程序,它由
联系人
作为对象/实体组成

以下是我删除组的代码:

    private void button_DeleteGroup_Click(object sender, EventArgs e)
    {
        var _selectedGroup = dataGridView_Groups.SelectedRows[0].DataBoundItem as Group;

        try
        {
            cgContext.Groups.Remove(_selectedGroup);
            cgContext.SaveChanges();

            PopulateGroupGrid();
            MessageBox.Show("Successfully deleted group from database!");
        }
        catch(Exception ex) { MessageBox.Show("Failed to delete group from database.\r\n\r\n" + ex); }
    }
如果我删除联系人所属的组以测试引用完整性,则会引发异常(应该是这样的):

“DELETE语句与引用约束冲突 “FK_dbo.Contacts_dbo.Groups_Group_Id”。冲突发生在中 数据库“ContactGroups”,表“dbo.Contacts”,第列 “组Id”。该语句已终止。“

然后我捕获这个异常并向用户显示一条消息。如果我随后去添加一个新组或联系人或执行任何操作,则事务失败,出现与之前相同的异常:

“DELETE语句与引用约束冲突 “FK_dbo.Contacts_dbo.Groups_Group_Id”。冲突发生在中 数据库“ContactGroups”,表“dbo.Contacts”,第列 “组Id”。该语句已终止。“

因此,很明显,当初始异常发生时,我并没有清算/结束交易或其他事情。我做错了什么或遗漏了什么?

从实体框架中的无效实体状态回滚 在实体框架中存在约束冲突或其他无效实体状态的情况下,有必要将状态恢复为有效/良好状态,以便继续保持更改

详细描述如何执行此操作

背景-发生FK约束冲突的原因 Contacts表和Groups表之间存在外键约束。根据外键(FK)
FK\u dbo.Contacts\u dbo.Groups\u group\u Id,每个联系人都有一个对组的引用

在上面的代码中,删除了一个组。执行此操作之前,应进行检查以确保没有引用(位于)该组的联系人,或者应删除该组中的联系人。方法将取决于您的业务逻辑


一旦删除了依赖项(即通过Contacts.GroupId引用组的任何联系人),则可以删除该组而不会出现FK冲突。

实体框架也称为持久性存储。因为它可以持久化实体的状态以及原始值和修改值。它实际上跟踪实体

EntityStateEntry具有EF中每个实体的条目。所以,当您调用
cgContext.Groups.Remove(_selectedGroup)
时,它会将实体的状态更改为deleted

现在,您正在删除一个有关联人员的组。因此,引用完整性不允许您删除
\u selectedGroup
,您会得到错误。但是
\u selectedGroup
的状态保留为
已删除
。现在,当您要添加一个新组时,在添加组后,您将调用
cgContext.SaveChange()
。这将尝试保存更改-添加新组和删除
\u selectedGroup
。但同样,删除违反了FK,并且您会得到相同的错误

要使其正常工作,可以使用
TransactionScope
。请参阅用法。

使用WillCascadeOnDelete(true)作为WithOptional选项

  modelBuilder.Entity<Parent>()
  .HasMany<Child>(c => c.Children)
  .WithOptional(x => x.Parent)
  .WillCascadeOnDelete(true);
对于.HasMany(…)。WithMany(…)Include是可以的


抱歉,这与发生错误无关。我强迫它发生,以便测试引用完整性。我想知道为什么在第一次抛出异常后,同一个异常会立即与其他CRUD操作一起继续抛出。好吧,那么您预期会出现异常。如果你是说问题在于你不能回滚它以便测试其他更改,那么看看这个:好的,谢谢,这有点帮助。这似乎应该有一个更标准化的答案。再次感谢:)当然。对不起,我误读了这个问题——我本应该拿起“应该”这个词的!非常感谢您的回答:)我可能最终会使用它或创建如下回滚方法:public void rollback(){dataContext.Dispose();dataContext=new myenties(yourConnection);}transactionScope是更好的方法吗?
  var adv = db.Adv.Include(b => b.Features)
                  .Include(b => b.AdvDetails)
                  .Include(b => b.AdvGallery)
                  .FirstOrDefault(b => b.Id == id);
  db.Adv.Remove(adv);