实体框架代码第一一对多级联错误

本文关键字:一对多 级联 错误 一一 框架 代码 实体 | 更新日期: 2023-09-27 18:03:45

我有4个模型类在我的Asp。Net Mvc项目。我首先使用实体框架代码(自动迁移)。当运行update-database命令时,我得到以下错误;

引入外键约束FK_dbo.Tickets_dbo。表'Tickets'上的Users_CreatedUserId'可能导致循环或多个级联路径。指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他外键约束。无法创建约束或索引。见前面的错误。

有什么问题吗?

//Company Class
public class Company
{
    public int Id { get; set; }
    [Required, StringLength(100)]
    public string Title { get; set; }
    public virtual ICollection<User> Users { get; set; } = new HashSet<User>();
}
//User Class
public class User
{
    public int Id { get; set; }
    [Required, StringLength(50)]
    public string UserName { get; set; }
    [Required, StringLength(100)]
    public string FullName { get; set; }
    public int CompanyId { get; set; }
    public virtual Company Company { get; set; }
}
//Ticket Class
public class Ticket
{
    public int Id { get; set; }
    [Required]
    public DateTime CreationDate { get; set; }
    [Required, StringLength(100)]
    public string Title { get; set; }
    public bool IsClosed { get; set; }
    public int CreatedUserId { get; set; }
    public virtual User CreatedUser { get; set; }
    public virtual ICollection<TicketMessage> Messages { get; set; } = new HashSet<TicketMessage>();
}
//TicketMessage Class
public class TicketMessage
{
    public int Id { get; set; }
    public DateTime Date { get; set; }
    [Required]
    public string Message { get; set; }
    public int UserId { get; set; }
    public virtual User User { get; set; }
    public int TicketId { get; set; }
    public virtual Ticket Ticket { get; set; }
}

实体框架代码第一一对多级联错误

如果您删除一个模型(父模型)中的一条记录,它将删除与它相关的子模型中的所有记录。在本例中,Users模型是具有许多Tickets和TicketMessages的父模型,因此当您删除一个用户时,级联删除也会删除所有用户的Tickets和TicketMessages。当模型具有导航属性时,EF会自动分配一个外键。外键创建了模型之间的关系,这意味着当"子"模型中的记录依赖于外键作为你试图删除的记录的主键时,你不能删除一个模型中的记录。

在您的情况下,正如评论所述,您的User模型与Ticket和TicketMessages都具有一对多关系,您的Ticket模型与TicketMessages具有一对多关系。这意味着删除一条User记录将删除与该UserID关联的所有TicketMessages和ticket,除了(对系统而言)具有该UserID的TicketMessage也可能使用未被UserID级联删除的TickedID。因此会出现错误,因为这会破坏外键关系。

有两个解决方案:

1 -修改您的设计,您的TicketMessages模型已经通过Ticket ID与Ticket建立了关系,因此与UserID建立了关系,因为UserID与Ticket模型中的Ticket ID相关联。因此,您可以从TicketMessage模型中删除UserID关系,这是不需要的。这样你的问题就解决了。在我看来,这确实是正确的解决方案,因为问题出在你的设计上。

2 -如果你因为某些原因我不能察觉到你想要保持这种关系,你可以禁用级联删除:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
    modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
}

这两行分别删除了一对多和多对多级联删除约定。你可以根据自己的需要保留或移除它们。

您还可以使用以下命令删除单个级联删除关系:

modelBuilder.Entity<ParentEntity>()
.HasMany(p => p.Children)
.WithRequired()
.HasForeignKey(c => c.ParentEntityId)
.WillCascadeOnDelete(false);

我强烈推荐解决方案1,从TicketMessages模型中删除UserID,您的TicketMessages已经通过TicketMessages模型和Ticket模型之间的关系链接到UserID。

edit—我突然想到,您可能希望TicketMessages和User之间的关系表示写消息的人,而这个人不是创建票据的同一用户。如果是这种情况,我仍然建议删除与User表的关系,而是使用一个字段,在这个字段中,您可以填充任何您想要在创建时与该Ticket Message关联的用户信息,例如Name。或者,您也可以保留UserID字段,但不带导航属性,从而删除外键关系。然后,在检索信息时,可以通过将此UserID与User表中的UserID匹配来调用用户信息。

谢谢你的回答,Rob!我用下面的代码解决了这个问题。

 modelBuilder.Entity<User>()
          .HasMany(e => e.TicketMessages)
          .WithRequired(e => e.User)
          .WillCascadeOnDelete(false);