如何配置实体框架级联删除以使用一对多关系正常工作?

时间:2017-07-26 22:43:13

标签: c# entity-framework

在此处研究级联删除和浏览问题后,我认为以下方案可以正常工作

实体有很多:

public partial class master
{
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public master()
        {
            analysis = new HashSet<analysis>();
        }

        [Key]
        public int id { get; set; }

        [StringLength(50)]
        public string description { get; set; }

        public virtual ICollection<analysis> analysis { get; set; }
}

实体有一个:

public partial class analysis
{
        [Key]
        public int id { get; set; }

        [StringLength(50)]
        public string description { get; set; }

        public int? master_id { get; set; }

        public virtual master master { get; set; }
}

analysis实体上的外键可以为空,因此当尝试删除master记录时,级联删除会自动将FK设置为​​null。

该配置位于我的Context

public class Context : DbContext
    {
        public Context() : base("Context")
        {
            this.Configuration.LazyLoadingEnabled = true;
            Database.SetInitializer(new DropCreateDatabaseIfModelChanges<Context>());
        }

        public virtual DbSet<master> master { get; set; }
        public virtual DbSet<analysis> analysis { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<master>()
                .HasMany(e => e.analysis)
                .WithOptional(e => e.master)
                .HasForeignKey(e => e.master_id)
                .WillCascadeOnDelete(true);
        }
    }

然后,当我尝试通过将id传递到以下内容时删除master记录(通用repo片段,在删除没有分析的master记录时,这样可以正常工作):

public void Delete(int id)
{
        var entity = FindByKey(id);
        _dbSet.Remove(entity);
        _context.SaveChanges();
}

我收到错误

  

无法删除或更新父行:外键约束失败

在此记录上。我在这里错过了什么?

1 个答案:

答案 0 :(得分:1)

使用CascaseOnDelete应该镜像数据库上的级联规则。使用CodeFirst将关系设置为Required时,EF会将映射和架构中的这两者映射为删除级联。对于可选关系,情况并非如此,它假设删除父级将使子级孤立,因为子级由于其无法使用FK而接受没有父级的存在。但是,如果不了解子记录,它就无法清除FK中的ID或删除数据,因此它依赖于DB设置的任何内容。

您仍然可以使用.WillCascadeOnDelete(),但要使其工作,上下文需要了解子项。例如,在新的背景下:

var master = _db.Masters.Find(id);
_db.Masters.Remove(master);

这通常会因FK约束错误而失败。 (SQL Server)错误消息与您的不同,所以我怀疑Tetsuya是不同的提供者?

要解决此问题,您可以使用:

var master = _db.Masters.Include(x=>x.analysis).Find(id);
_db.Masters.Remove(master);

虽然对于包含所有孩子的较大图表的对象来说这可能很乏味。

作为一般规则,如果要使用级联删除,则需要确保数据库架构设置为具有级联删除行为。使用无效FK和级联删除规则,原始代码应按预期运行。或者,将级联规则设置为“Set to Null”将使子记录孤立为空FK。 (EF没有错误)