2014-01-23 59 views
11

因此,在这里有几个类似的问题,但我仍然有问题,以确定我在我的简化方案中错过了什么。实体框架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'行?

回答

11

这取决于你是否希望实体框架删除的孩子,或者你希望数据库照顾它。

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

所以你不能简单地创建一个只有密钥填充的“虚拟”实体,并期望孩子被删除。

为了这个工作,你必须让数据库处理删除。

但子表上的外键必须启用级联删除。如果是这样,实体框架只是为父对象创建一条删除语句,并且数据库也知道要删除这些子对象。

如果需要关系,Entity Framework会创建一个默认启用级联删除的外键,就像您的情况一样。 (外键不能为空)。

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

-1

在Visual Studio中打开模型文件。右键单击父 - 子关系并选择属性。

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

enter image description here

干杯 -

+8

的OP问题是代码第一位。此解决方案仅适用于Model First。 – vidalsasoon

15

我认为最好重写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(真)

+0

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