级联删除与实体框架 - 由EF删除的相关实体

时间:2011-03-27 10:39:44

标签: entity-framework cascading-deletes

我在实体框架中删除了一个问题。简而言之,EF显式尝试从数据库中删除实体,即使我已经明确地将EF配置为在数据库中使用级联删除。

我的设计:

我有三种实体类型,MainEntityEntityTypeAEntityTypeB。 EF已被配置为在删除EntityTypeAEntityTypeB时使用级联删除。换句话说,如果我删除MainEntity的实例,我也希望删除所有相关的EntityTypeAEntityTypeB实例。我从不删除EntityTypeAEntityTypeB而不删除其父级。

我的问题是EF明确地为DELETE发出EntityTypeA语句,导致我的应用程序崩溃。

这就是我的模型:

关系具​​有以下非默认配置:

  • MainEntity -> EntityTypeA OnDelete: Cascade
  • MainEntity -> EntityTypeB OnDelete: Cascade

关系EntityTypeA -> EntityTypeBOnDelete: None

数据库内容

INSERT INTO MainEntities (Name) values ('Test')
insert into EntityTypeA (MainEntityID) VALUES (1)
insert into EntityTypeB (MainEntityID, EntityTypeAId) VALUES (1, 1)
insert into EntityTypeB (MainEntityID, EntityTypeAId) VALUES (1, 1)

我的代码:

class Program
{
   static void Main(string[] args)
   {
      var context = new Model1Container();
      var mainEntity = context.MainEntities.Include("EntityTypeA").SingleOrDefault();
      context.DeleteObject(mainEntity);
      context.SaveChanges();
   }
}

会发生什么

当我调用SaveChanges时,Entity Framework在数据库中执行以下操作:

exec sp_executesql N'delete [dbo].[EntityTypeA]
where ([Id] = @0)',N'@0 int',@0=1

这会导致外键违规,因为EntityTypeB的表中有一些项引用了EntityTypeA实例。

问题

为什么Entity Framework会为EntityTypeA实例发出显式删除,即使我已将实体框架配置为使用级联删除?如果我删除Include(“EntityTypeA”),它将再次开始工作。

2 个答案:

答案 0 :(得分:41)

这正是级联删除行为在EF中的表现。在EF设计器中的关系上设置 Cascade 指示EF为每个已加载的相关实体执行DELETE语句。它没有说明数据库中的ON CASCADE DELETE

使用EF时设置级联删除需要两个步骤:

  • 在EF设计器中设置 Cascade 关系。在删除父实体之前,必须删除所有已加载的相关实体的指示上下文。如果没有发生这种情况,EF将抛出异常,因为内部状态将检测到加载的子级与任何现有父级实体无关,即使需要关系也是如此。我不确定在执行父实体的删除语句之前或之后是否发生这种情况但没有区别。 EF在执行修改后不会重新加载相关实体,因此它根本不知道数据库中触发的级联删除。
  • 在数据库中的关系上设置ON CASCADE DELETE。这将指示SQL在删除父级时删除未加载到上下文的所有相关记录。

EF中级联删除的实现很奇怪且效率很低,但这就是它的行为方式,如果你想使用它,你必须修改你的应用程序才能在这种情况下正常运行。

答案 1 :(得分:5)

可以在数据库中的FK约束上设置级联删除,而不是在EF设计器上。

以下是Sql Server Management Studio(SSMS)关于如何设置级联删除的可视步骤。

注意完成后,在尝试删除之前,请不要忘记对数据库更新edmx

enter image description here

我在博客上更深入地讨论了这个问题:Entity Framework Cascading Deletes; Set it from the database.