外键约束问题?

时间:2013-08-10 12:33:07

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

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

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

以下是我的实体:

SupportTicket:

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

这里有什么问题?我没有看到什么是错的。

1 个答案:

答案 0 :(得分:2)

问题是两个实体都需要UserProfile

UserProfileSupportTicketSupportTicketMessage之间有三个必需的一对多关系:

  1. 一个UserProfile - 许多SupportTicket s
  2. 一个UserProfile - 许多SupportTicketMessage s
  3. 一个SupportTicket - 许多SupportTicketMessage s
  4. (左侧是主体(具有关系的主键),右侧是从属(具有关系的外键)。)

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

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

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

    SQL Server中不允许这样做以及异常的原因。

    为了解决问题,您必须“破坏”至少一个关系的级联删除路径。您可以通过建立关系可选(即:删除导航属性中的[Required]属性之一)或通过显式禁用级联删除来实现。我会选择后一个选项,因为将关系从 required 更改为可选会改变业务规则。我会禁用关系1和2的级联删除,因为删除UserProfile可能不应删除所有SupportTicketSupportTicketMessage,而应将票证和消息分配给某些“匿名”默认用户,因此当用户想要离开系统时,故障单历史记录不会丢失。

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

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

    (如果UserProfile中的导航集合引用SupportTicketSupportTicketMessage,则必须使用WithMany调用lambda参数,例如WithMany(u => u.SupportTickets) }和WithMany(u => u.SupportTicketMessages)。)