EntityFramewok:如何配置Cascade-Delete以使外键无效

Ale*_*lex 30 entity-framework entity-framework-5

EntityFramework的文档声明可能存在以下行为:

如果依赖实体上的外键可以为空,则Code First不会在关系上设置级联删除,并且当删除主体时,外键将设置为null.

(来自http://msdn.microsoft.com/en-us/jj591620)

但是,我无法实现这样的行为.

我使用代码优先定义了以下实体:

public class TestMaster
{
    public int Id { get; set; }
    public string Name { get; set; }        
    public virtual ICollection<TestChild> Children { get; set; }       
}

public class TestChild
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual TestMaster Master { get; set; }
    public int? MasterId { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

以下是Fluent API映射配置:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<TestMaster>()
                    .HasMany(e => e.Children)
                    .WithOptional(p => p.Master).WillCascadeOnDelete(false);

        modelBuilder.Entity<TestChild>()
                    .HasOptional(e => e.Master)
                    .WithMany(e => e.Children)
                    .HasForeignKey(e => e.MasterId).WillCascadeOnDelete(false);
    }
Run Code Online (Sandbox Code Playgroud)

外键可以为空,导航属性被映射为可选,因此我希望级联删除工作如MSDN所述 - 即取消所有子项的MasterID,然后删除主对象.

但是当我实际尝试删除时,我收到FK违规错误:

 using (var dbContext = new TestContext())
        {
            var master = dbContext.Set<TestMaster>().Find(1);
            dbContext.Set<TestMaster>().Remove(master);
            dbContext.SaveChanges();
        }
Run Code Online (Sandbox Code Playgroud)

在SaveChanges()上,它抛出以下内容:

System.Data.Entity.Infrastructure.DbUpdateException : An error occurred while updating the entries. See the inner exception for details.
----> System.Data.UpdateException : An error occurred while updating the entries. See the inner exception for details.
----> System.Data.SqlClient.SqlException : The DELETE statement conflicted with the REFERENCE constraint "FK_dbo.TestChilds_dbo.TestMasters_MasterId". The conflict occurred in database "SCM_Test", table "dbo.TestChilds", column 'MasterId'.
The statement has been terminated.
Run Code Online (Sandbox Code Playgroud)

我做错了什么或者我误解了MSDN说的是什么?

Sla*_*uma 44

它确实如所描述的那样工作,但MSDN上的文章没有强调它只有在孩子被加载到上下文中时才有效,而不仅仅是父实体.因此,Find您必须使用Include(或以任何其他方式将子项加载到上下文中)而不是使用(仅加载父项);

using (var dbContext = new TestContext())
{
    var master = dbContext.Set<TestMaster>().Include(m => m.Children)
        .SingleOrDefault(m => m.Id == 1);
    dbContext.Set<TestMaster>().Remove(master);
    dbContext.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)

这将从数据库中删除master,将Child实体中的所有外键设置null为,并将子项的UPDATE语句写入数据库.

  • 大胆的文字救了我.延迟加载很棒,但确保在删除前加载子对象... (7认同)