constraints翻译 - sql constraint用法




外键约束可能会导致循环或多个级联路径? (6)

当我尝试向我的表添加约束时,遇到问题。 我收到错误:

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

我的约束是在Code表和employee表之间。 Code表包含IdNameFriendlyNameTypeValue 。 该employee有许多字段参考代码,以便可以为每种类型的代码提供参考。

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

任何想法我可以做到这一点?


SQL Server对级联路径进行简单的计数,而不是试图确定是否存在任何周期,它将假设最差并拒绝创建参考操作(CASCADE):您可以并且应该仍然创建没有参考操作的约束。 如果你不能改变你的设计(否则会损害你的设计),那么你应该考虑使用触发器作为最后的手段。

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


一个具有多个级联路径的典型情况是这样的:一个包含两个细节的主表,比如说“Master”和“Detail1”和“Detail2”。 这两个细节都是级联删除。 到目前为止没有问题。 但是如果这两个细节与其他表都有一对多的关系(比如说“SomeOtherTable”)呢? SomeOtherTable具有Detail1ID列和Detail2ID列。

Master { ID, masterfields }

Detail1 { ID, MasterID, detail1fields }

Detail2 { ID, MasterID, detail2fields }

SomeOtherTable {ID, Detail1ID, Detail2ID, someothertablefields }

换句话说:SomeOtherTable中的某些记录与Detail1-记录链接,SomeOtherTable中的某些记录与Detail2记录链接。 即使保证SomeOtherTable记录从不属于两个Details,现在也不可能使两个细节的SomeOhterTable记录级联删除,因为从Master到SomeOtherTable(一个通过Detail1,一个通过Detail2)存在多条级联路径。 现在你可能已经明白了这一点。 这是一个可能的解决方案:

Master { ID, masterfields }

DetailMain { ID, MasterID }

Detail1 { DetailMainID, detail1fields }

Detail2 { DetailMainID, detail2fields }

SomeOtherTable {ID, DetailMainID, someothertablefields }

所有ID字段都是关键字段并自动递增。 症结在于Detail表格的DetailMainId字段。 这些领域都是关键和参照性的限制。 现在可以通过仅删除主记录来级联删除所有内容。 不足之处在于,对于每个detail2记录的每个detail1记录AND,还必须有一个DetailMain记录(实际上首先创建该记录以获取正确且唯一的id)。


我会指出(功能上)SCHEMA和DATA中的周期和/或多个路径之间存在很大差异。 尽管DATA中的循环和可能的多路径可能肯定会使处理复杂化并导致性能问题(“正确”处理的成本),但这些特征在模式中的成本应接近于零。

由于RDB中的大多数表观循环出现在层次结构(组织结构图,部分,子部分等)中,所以很不幸SQL Server假设为最差; 即模式循环==数据循环。 事实上,如果你使用RI限制,你实际上不能在数据中建立一个循环!

我怀疑多路径问题是相似的; 即模式中的多条路径不一定意味着数据中有多条路径,但我对多路径问题的经验较少。

当然,如果SQL Server 确实允许循环,它仍然会受到32的深度,但这对大多数情况来说可能是足够的。 (太糟糕了,这不是数据库设置!)

“而不是删除”触发器也不起作用。 第二次访问表时,触发器将被忽略。 所以,如果你真的想模拟一个级联,你将不得不在循环中使用存储过程。 然而,取代删除触发器可以用于多路径情况。

Celko提出了一种“更好”的方式来表示不引入循环的层次结构,但存在折衷。



这是因为Emplyee可能会收集其他实体说资格和资格可能有一些其他集合大学,例如

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

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

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

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

或完全关闭此功能:

modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();




constraints