外键约束问题?

Posted

技术标签:

【中文标题】外键约束问题?【英文标题】:Foreign key constraint issue? 【发布时间】:2013-08-12 06:49:39 【问题描述】:

我对我的 EF 代码优先数据库进行了一些更改,当我尝试更新它时,我现在收到以下错误:

在表“SupportTicketMessages”上引入 FOREIGN KEY 约束“FK_dbo.SupportTicketMessages_dbo.SupportTickets_Ticket_Id”可能会导致循环或多个级联路径。指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。

这是我的实体:

支持票:

public class SupportTicket
    
        [Key]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int Id  get; set; 

        [Required]
        public string Title  get; set; 

        [Required]
        public string Text  get; set; 

        [Required]
        public TicketUrgency Urgency  get; set; 

        [Required]
        public TicketStatus Status  get; set; 

        [Required]
        public virtual UserProfile Owner  get; set; 

        [Required]
        public DateTime Date  get; set; 

SupportTicketMessage:

public class SupportTicketMessage
    
        [Key]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int Id  get; set; 

        [Required]
        public virtual UserProfile Author  get; set; 

        [Required]
        public string Text  get; set; 

        [Required]
        public DateTime Date  get; set; 

        [Required]
        public virtual SupportTicket Ticket  get; set; 

        [Required]
        public int MessageNumber  get; set; 
    

这里有什么问题?我看不出有什么问题。

【问题讨论】:

您已指定级联删除...***.com/questions/10523291/… - 类似问题 @MilenPavlov 但我不明白问题出在哪里。而且我从来没有指定级联删除 【参考方案1】:

问题是两个实体都需要UserProfile

UserProfileSupportTicketSupportTicketMessage 之间存在三个必需一对多关系:

    一个UserProfile - 许多SupportTickets 一个UserProfile - 许多SupportTicketMessages 一个SupportTicket - 许多SupportTicketMessages

(左侧是主体(具有关系的主键),右侧是从属(具有关系的外键)。)

对于所需的一对多关系,EF 默认会向数据库添加级联删除,即如果删除了上面左侧的实体,则应自动删除右侧的所有依赖实体。

如果您现在要删除 UserProfile,您将有两个级联删除路径到 SupportTicketMessage 表,即:

UserProfile -> SupportTicket -> SupportTicketMessage(因为关系 1 和 3) UserProfile -> SupportTicketMessage(因为关系 2)

这在 SQL Server 中是不允许的以及异常的原因。

为了解决问题,您必须“破坏”至少一个关系的级联删除路径。您可以通过使关系可选(即:删除导航属性上的[Required] 属性之一)或显式禁用级联删除来做到这一点。我会选择后一个选项,因为将关系从 required 更改为 optional 有点改变业务规则。我会为关系 1 和 2 禁用级联删除,因为也许删除 UserProfile 不应该删除所有 SupportTickets 和 SupportTicketMessages 而是应该将票证和消息分配给一些“匿名”默认用户,所以当用户想要离开系统时,工单历史不会丢失。

必须使用 Fluent API 禁用级联删除:

modelBuilder.Entity<SupportTicket>()
    .HasRequired(s => s.Owner)
    .WithMany()
    .WillCascadeOnDelete(false);

modelBuilder.Entity<SupportTicketMessage>()
    .HasRequired(s => s.Author)
    .WithMany()
    .WillCascadeOnDelete(false);

(如果您在 UserProfile 中有导航集合引用 SupportTickets 和 SupportTicketMessages,则必须使用带有 lambda 参数的 WithMany 调用,例如 WithMany(u =&gt; u.SupportTickets)WithMany(u =&gt; u.SupportTicketMessages)。)

【讨论】:

哇,多么高质量的答案!非常感谢,我现在明白了 - 效果很好!非常感谢您的帮助。

以上是关于外键约束问题?的主要内容,如果未能解决你的问题,请参考以下文章

主键约束,外键约束,空值约束,默认值约束,唯一约束,检查约束的各个作用是啥?

怎么添加外键约束

Oracle定义约束外键约束

数据库外键约束?

SQL中如何为表添加外键约束

高级c#中三层架构中存在外键约束怎么删除