实体框架6:代码优先级联删除

时间:2014-01-23 16:37:06

标签: c# sql entity-framework entity-framework-6

所以这里有几个类似的问题,但我仍然有问题确定我在简化场景中缺少的是什么。

假设我有以下表格,以我自己的名字命名:

'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();

实体框架尝试执行以下操作:

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.

那么我的问题是我究竟缺少什么以确保实体框架知道它必须在删除父项之前删除'JohnsChildTable'行?

3 个答案:

答案 0 :(得分:17)

我认为最好覆盖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 :(得分:12)

这取决于您是希望实体框架删除子项,还是希望数据库处理它。

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

因此,您不能简单地仅使用填充的密钥创建“虚拟”实体,并期望删除子项。

要使其正常工作,您必须让数据库处理删除操作。

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

如果需要关系,

实体框架会创建一个默认启用级联删除的外键,就像您的情况一样。 (外键不能为空)。

如果您自己创建了数据库,则必须记住启用它。

答案 2 :(得分:-1)

在Visual Studio中打开模型文件。右键单击Parent-Child关系,然后选择Properties。

在End1 OnDelete属性上,该值可能为None。另一种选择是Cascade;把它设置为那个。现在删除父级会将删除级联到其子级。

enter image description here

干杯 -

相关问题