EntityFramewok:如何配置Cascade-Delete来取消外键 [英] EntityFramewok: How to configure Cascade-Delete to nullify Foreign Keys

查看:117
本文介绍了EntityFramewok:如何配置Cascade-Delete来取消外键的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

EntityFramework的文档规定,可以执行以下行为:


如果依赖实体上的外键为空,Code First将
没有设置关联关系的级联删除,当主体为
时,外键将被设置为null。




>

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



我有以下代码定义的以下实体:

  public class TestMaster 
{
public int Id {get;组; }
public string Name {get;组; }
public virtual ICollection< TestChild>孩子{get;组; }
}

public class TestChild
{
public int Id {get;组; }
public string Name {get;组; }
public virtual TestMaster Master {get;组; }
public int? MasterId {get;组;
}

以下是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);
}

外键为可空,导航属性映射为可选,所以我期望级联删除按照MSDN的描述工作,即删除所有子项的MasterID,然后删除主对象。



但是当我真的尝试删除时,我得到了FK违规错误:

  using(var dbContext = new TestContext())
{
var master = dbContext .SET< TestMaster>()查找(1);
dbContext.Set&TestMaster>()。Remove(master);
dbContext.SaveChanges();
}

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

  System.Data.Entity.Infrastructure.DbUpdateException:更新条目时出错。查看内部例外情况。 
----> System.Data.UpdateException:更新条目时发生错误。查看内部例外情况。
----> System.Data.SqlClient.SqlException:DELETE语句与REFERENCE约束FK_dbo.TestChilds_dbo.TestMasters_MasterId冲突。冲突发生在数据库SCM_Test,表dbo.TestChilds,MasterId列。
该语句已被终止。

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

解决方案

它的作用确实如上所述,但MSDN上的文章错过了强调,它只有当孩子被加载到上下文中才有效以及不仅父母实体。所以,而不是使用 Find (仅加载父级),您必须使用e $加载 Include (或任何其他使用(var dbContext = new TestContext())
{$($)

 .SingleOrDefault(m => m.Id == 1); 
dbContext.Set&TestMaster>()。Remove(master);
dbContext.SaveChanges();
}

这将从数据库中删除主数据库,将所有外键设置为 Child entities to null ,并将孩子的UPDATE语句写入数据库。


EntityFramework's documentation states that the following behavior is possible:

If a foreign key on the dependent entity is nullable, Code First does not set cascade delete on the relationship, and when the principal is deleted the foreign key will be set to null.

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

However, I cannot achieve such a behavior.

I have the following Entities defined with code-first:

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; }
}

Here is the Fluent API mapping configuration:

    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);
    }

Foreign Key is nullable, navigation property is mapped as Optional, so I expect the cascade delete to work as described as MSDN - i.e. to nullify MasterID's of all children and then delete the Master object.

But when I actually try to delete, I get the FK violation error:

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

On SaveChanges() it throws the following:

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.

Am I doing something wrong or did I misunderstood what the MSDN says?

解决方案

It works indeed as described but the article on MSDN misses to emphasize that it only works if the children are loaded into the context as well, not only the parent entity. So, instead of using Find (which only loads the parent) you must use eager loading with Include (or any other way to load the children into the context):

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

This will delete the master from the database, set all foreign keys in the Child entities to null and write UPDATE statements for the children to the database.

这篇关于EntityFramewok:如何配置Cascade-Delete来取消外键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆