我有一个问题,当我试图添加约束到我的表。我得到了错误:

在表'Employee'上引入外键约束'FK74988DB24B3C886'可能会导致循环或多个级联路径。指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他外键约束。

我的约束是在Code表和employee表之间。Code表包含Id, Name, FriendlyName, Type和Value。雇员有许多引用代码的字段,因此每种类型的代码都有一个引用。

我需要字段被设置为空,如果引用的代码被删除。

你知道我该怎么做吗?


当前回答

这是数据库触发策略类型的错误。触发器是代码,可以向级联关系(如级联删除)添加一些智能或条件。你可能需要专门化相关的表选项,比如关闭CascadeOnDelete:

protected override void OnModelCreating( DbModelBuilder modelBuilder )
{
    modelBuilder.Entity<TableName>().HasMany(i => i.Member).WithRequired().WillCascadeOnDelete(false);
}

或者完全关闭此功能:

modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

其他回答

我用ASP解决了这个问题。NET Core 2.0和EF Core 2.0是按以下顺序执行的:

在包管理控制台(PMC)中运行update-database命令来创建数据库(这将导致“引入外键约束…”可能导致循环或多个级联路径。"错误) 在PMC中运行script-migration -Idempotent命令,创建一个可以不受现有表/约束而运行的脚本 使用结果脚本并找到ON DELETE CASCADE并替换为ON DELETE NO ACTION 对数据库执行修改后的SQL

现在,您的迁移应该是最新的,级联删除应该不会发生。

太糟糕了,我在实体框架核心2.0中找不到任何方法来做到这一点。

好运!

这是因为员工可能收集其他实体的资格和资格可能有一些其他收集大学 如。

public class Employee{
public virtual ICollection<Qualification> Qualifications {get;set;}

}

public class Qualification{

public Employee Employee {get;set;}

public virtual ICollection<University> Universities {get;set;}

}

public class University{

public Qualification Qualification {get;set;}

}

在DataContext上,它可能如下所示

protected override void OnModelCreating(DbModelBuilder modelBuilder){

modelBuilder.Entity<Qualification>().HasRequired(x=> x.Employee).WithMany(e => e.Qualifications);
modelBuilder.Entity<University>.HasRequired(x => x.Qualification).WithMany(e => e.Universities);

}

在这种情况下,存在从员工到资格,从资格到大学的链条。所以它向我抛出了相同的异常。

我变了之后,这招很管用

    modelBuilder.Entity<Qualification>().**HasRequired**(x=> x.Employee).WithMany(e => e.Qualifications); 

To

    modelBuilder.Entity<Qualification>().**HasOptional**(x=> x.Employee).WithMany(e => e.Qualifications);

大量数据库更新来抵消pk:做一个数据库副本代替。

特殊用例:A公司使用与b公司具有相同模式的数据库,因为他们已经合并,所以他们希望使用单个数据库。因此,来自公司B数据库的许多表的主键必须偏移,以避免与公司A的记录发生冲突。

一种解决方案是将外键定义为ON UPDATE CASCADE,并抵消带有外键的主键。但是如果你这样做的话会有很多障碍(味精1785,味精8102,…)。

因此,我想到的一个更好的主意是简单地复制数据库,DROP和re CREATE必须有其PKs|FKs偏移量的表,并复制数据(在这样做的同时,偏移主键和外键)。

避免所有的麻烦。

多个套管路径的典型情况如下: 一个有两个细节的主表,我们说“master”和“Detail1”和“Detail2”。这两个细节都是级联删除。到目前为止还没有问题。但是,如果两个细节都与其他表(比如“SomeOtherTable”)有一对多的关系呢?SomeOtherTable有一个Detail1ID-column和一个Detail2ID-column。

Master { ID, masterfields }

Detail1 { ID, MasterID, detail1fields }

Detail2 { ID, MasterID, detail2fields }

SomeOtherTable {ID, Detail1ID, Detail2ID, someothertablefields }

In other words: some of the records in SomeOtherTable are linked with Detail1-records and some of the records in SomeOtherTable are linked with Detail2 records. Even if it is guaranteed that SomeOtherTable-records never belong to both Details, it is now impossible to make SomeOhterTable's records cascade delete for both details, because there are multiple cascading paths from Master to SomeOtherTable (one via Detail1 and one via Detail2). Now you may already have understood this. Here is a possible solution:

Master { ID, masterfields }

DetailMain { ID, MasterID }

Detail1 { DetailMainID, detail1fields }

Detail2 { DetailMainID, detail2fields }

SomeOtherTable {ID, DetailMainID, someothertablefields }

所有ID字段都是键字段和自动递增字段。问题的关键在于Detail表的DetailMainId字段。这些字段既是关键约束,又是参考约束。现在可以通过只删除主记录来级联删除所有内容。缺点是,对于每个detail1记录和每个detail2记录,还必须有一个detailmain记录(实际上是首先创建该记录以获得正确和唯一的id)。

我想指出的是(从功能上)SCHEMA和DATA中的循环和/或多条路径之间有很大的区别。虽然DATA中的循环和多路径肯定会使处理复杂化并导致性能问题(“适当”处理的成本),但模式中这些特征的成本应该接近于零。

由于rdb中大多数明显的循环发生在层次结构中(组织结构图、部分、子部分等),不幸的是SQL Server假设了最坏的情况;即,模式周期==数据周期。事实上,如果您使用RI约束,您实际上无法在数据中构建一个循环!

我认为多路径问题与此类似;也就是说,模式中的多条路径并不一定意味着数据中的多条路径,但我对多路径问题的经验较少。

当然,如果SQL Server允许循环,它的深度仍然是32,但这对于大多数情况来说可能已经足够了。(可惜这不是一个数据库设置!)

“代替删除”触发器也不起作用。第二次访问表时,触发器将被忽略。所以,如果你真的想要模拟级联,你就必须在存在循环的情况下使用存储过程。但是,Instead-of-Delete-Trigger适用于多路径情况。

Celko提出了一种“更好的”表示层次结构的方法,这种方法不引入循环,但也有折衷之处。