【问题标题】: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; }
    }

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

【问题讨论】:

标签: c# .net database entity-framework relational-database


【解决方案1】:

问题是两个实体都需要UserProfile

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

  1. 一个UserProfile - 许多SupportTickets
  2. 一个UserProfile - 许多SupportTicketMessages
  3. 一个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)。)

【讨论】:

  • 哇,多么高质量的答案!非常感谢,我现在明白了 - 效果很好!非常感谢您的帮助。
猜你喜欢
  • 2020-07-09
  • 1970-01-01
  • 2020-03-16
  • 2010-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多