外键约束问题
本文关键字:问题 约束 | 更新日期: 2023-09-27 18:27:03
我已经对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; }
}
这里有什么问题?我不知道出了什么问题。
问题是两个实体中必需的UserProfile
。
UserProfile
、SupportTicket
和SupportTicketMessage
:之间需要三个一对多关系
- 一个
UserProfile
-多个SupportTicket
- 一个
UserProfile
-多个SupportTicketMessage
- 一个
SupportTicket
-多个SupportTicketMessage
s
(左侧是主体(具有关系的主键),右侧是从属(具有关系外键)。)
对于所需的一对多关系,EF默认情况下向数据库添加级联删除,即,如果删除了上面左侧的实体,则右侧的所有依赖实体都应自动删除。
如果您现在要删除一个UserProfile
,那么到SupportTicketMessage
表将有两个级联删除路径,即:
UserProfile
->SupportTicket
->SupportTicketMessage
(因为关系1和3)UserProfile
->SupportTicketMessage
(因为关系2)
这在SQL Server中是不允许的,以及异常的原因。
为了解决此问题,您必须"断开"至少一个关系的级联删除路径。您可以通过使关系可选(即:删除导航属性上的一个[Required]
属性)或显式禁用级联删除来实现这一点。我会选择后一个选项,因为将关系从必需更改为可选有点像更改业务规则。我会禁用关系1和2的级联删除,因为删除UserProfile
可能不应该删除所有SupportTicket
和SupportTicketMessage
,而是应该将票证和消息分配给某个"匿名"默认用户,这样当用户想要离开系统时,票证历史记录就不会丢失。
必须使用Fluent API禁用级联删除:
modelBuilder.Entity<SupportTicket>()
.HasRequired(s => s.Owner)
.WithMany()
.WillCascadeOnDelete(false);
modelBuilder.Entity<SupportTicketMessage>()
.HasRequired(s => s.Author)
.WithMany()
.WillCascadeOnDelete(false);
(如果您在UserProfile
中有引用SupportTicket
s和SupportTicketMessage
s的导航集合,则必须使用带有lambda参数的WithMany
调用,如WithMany(u => u.SupportTickets)
和WithMany(u => u.SupportTicketMessages)
。)