Entity Framework 6:基于代码的级联删除

16

这里有几个类似的问题,但是在我的简化场景中仍然存在我无法确定的问题。

假设我有以下表格,巧妙地以我的名字命名:

'JohnsParentTable' (Id, Description) 
'JohnsChildTable' (Id, JohnsParentTableId, Description)

最终生成的类看起来像这样

public class JohnsParentTable
{
    public int Id { get; set; }
    public string Description { get; set; }
    public virtual ICollection<JohnsChildTable> JohnsChildTable { get; set; }

    public JohnsParentTable()
    {
        JohnsChildTable = new List<JohnsChildTable>();
    }
}

internal class JohnsParentTableConfiguration : EntityTypeConfiguration<JohnsParentTable>
{
    public JohnsParentTableConfiguration()
    {
        ToTable("dbo.JohnsParentTable");
        HasKey(x => x.Id);
        Property(x => x.Id).HasColumnName("Id").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        Property(x => x.Description).HasColumnName("Description").IsRequired().HasMaxLength(50);
    }
}

public class JohnsChildTable
{
    public int Id { get; set; }
    public string Description { get; set; }
    public int JohnsParentTableId { get; set; }
    public JohnsParentTable JohnsParentTable { get; set; }
}

internal class JohnsChildTableConfiguration : EntityTypeConfiguration<JohnsChildTable>
{
    public JohnsChildTableConfiguration()
    {
        ToTable("dbo.JohnsChildTable");
        HasKey(x => x.Id);
        Property(x => x.Id).HasColumnName("Id").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        Property(x => x.Description).HasColumnName("Description").IsRequired().HasMaxLength(50);
        HasRequired(a => a.JohnsParentTable).WithMany(c => c.JohnsChildTable).HasForeignKey(a => a.JohnsParentTableId);
    }
}
在数据库中,我有一个父表中ID为1的行,以及与该父表相关联的两个子表中的行。如果我执行以下操作:
var parent = db.JohnsParentTable.FirstOrDefault(a => a.Id == 1)

该对象已正确填充。但是,如果我尝试删除该行:

var parent = new Data.Models.JohnsParentTable() { Id = 1 };
db.JohnsParentTable.Attach(parent);
db.JohnsParentTable.Remove(parent);

db.SaveChanges();

Entity Framework 尝试执行以下操作:

DELETE [dbo].[JohnsParentTable]
WHERE ([Id] = @0)
-- @0: '1' (Type = Int32)
-- Executing at 1/23/2014 10:34:01 AM -06:00
-- Failed in 103 ms with error: The DELETE statement conflicted with the REFERENCE constraint "FK_JohnsChildTable_JohnsParentTable". The conflict occurred in database "mydatabase", table "dbo.JohnsChildTable", column 'JohnsParentTableId'.
The statement has been terminated.

那么我的问题是,我是否遗漏了什么,以确保Entity Framework知道在删除父级之前必须删除“JohnsChildTable”的行?

3个回答

20
我认为最好重写OnModelCreating方法并添加以下代码。
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
   modelBuilder.Entity<JohnsChildTable>()
               .HasRequired(t=>t.JohnsParentTable)
               .WithMany(t=>t.JohnsChildTables)
               .HasForeignKey(d=>d.JohnsParentTableId)
               .WillCascadeOnDelete(true);

            base.OnModelCreating(modelBuilder);
}

我已经设置为 true WillCascadeOnDelete(true)

1
只是一个警告:据我所知,上面的代码不会使EF级联删除未加载到内存中的子项。 - Riva

13

这取决于您是希望Entity Framework删除子项,还是希望数据库来处理。

如果您希望EF为所有子项生成一个删除语句,并在删除父项之前执行这些语句,则必须先将所有子项加载到内存中。

所以您不能只创建一个只填充了键的“虚拟”实体,并期望子项被删除。

为了使其起作用,您必须让数据库处理删除。

但是,子表上的外键必须启用级联删除。 如果是这种情况,Entity Framework只会创建一个父项的删除语句,而数据库会知道同时删除子项。

如果关系是必需的(外键不能为空),那么Entity Framework默认会使用启用了级联删除的外键,就像在您的情况下一样。

如果是自己创建的数据库,则必须记得启用它。


-2
在Visual Studio中打开模型文件。右键单击父子关系,然后选择属性。
在End1 OnDelete属性上,值可能为None。另一个选项是Cascade;将其设置为该选项。现在删除父项将级联删除其子项。

enter image description here

干杯 -


8
OP的问题是关于Code First的。这个解决方案只适用于Model First。 - vidalsasoon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接