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

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

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

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

你知道我该怎么做吗?


当前回答

SQL Server对级联路径进行简单的计数,而不是试图计算是否存在任何循环,它假设最坏的情况并拒绝创建引用操作(cascade):您可以并且应该仍然在没有引用操作的情况下创建约束。如果你不能改变你的设计(或者这样做会损害一些东西),那么你应该考虑使用触发器作为最后的手段。

FWIW求解级联路径是一个复杂的问题。其他SQL产品将简单地忽略这个问题,并允许您创建循环,在这种情况下,它将是一场比赛,看看谁将最后覆盖的值,可能是设计师的无知(例如ACE/Jet这样做)。我知道一些SQL产品将尝试解决简单的情况。事实是,SQL Server甚至没有尝试,它通过禁止多个路径来保持超级安全,至少它会告诉你。

微软自己建议使用触发器而不是FK约束。

其他回答

SQL Server对级联路径进行简单的计数,而不是试图计算是否存在任何循环,它假设最坏的情况并拒绝创建引用操作(cascade):您可以并且应该仍然在没有引用操作的情况下创建约束。如果你不能改变你的设计(或者这样做会损害一些东西),那么你应该考虑使用触发器作为最后的手段。

FWIW求解级联路径是一个复杂的问题。其他SQL产品将简单地忽略这个问题,并允许您创建循环,在这种情况下,它将是一场比赛,看看谁将最后覆盖的值,可能是设计师的无知(例如ACE/Jet这样做)。我知道一些SQL产品将尝试解决简单的情况。事实是,SQL Server甚至没有尝试,它通过禁止多个路径来保持超级安全,至少它会告诉你。

微软自己建议使用触发器而不是FK约束。

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

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

或者完全关闭此功能:

modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

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

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

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

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

避免所有的麻烦。

听起来,你有一个OnDelete/OnUpdate动作在你现有的外键之一,这将修改你的代码表。

通过创建这个外键,你会创建一个循环问题,

例如,更新Employees,导致代码被一个On Update Action改变,导致Employees被一个On Update Action改变…等等……

如果你发布了两个表的表定义,以及你的外键/约束定义,我们应该能够告诉你问题在哪里…

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

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