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

C# 实体框架代码第一个一对多级联错误,c#,asp.net-mvc,entity-framework,ef-code-first,code-first,C#,Asp.net Mvc,Entity Framework,Ef Code First,Code First,在我的Asp.NETMVC项目中,我有4个模型类。我首先使用实体框架代码(自动迁移)。当我运行命令更新数据库时,我得到以下错误 在表“Tickets”上引入外键约束“FK_dbo.Tickets_dbo.Users_CreatedUserId”可能会导致循环或多个级联路径。指定“在删除时不执行操作”或“在更新时不执行操作”,或修改其他外键约束。 无法创建约束或索引。请参阅前面的错误 有什么问题 //Company Class public class Company { public i

在我的Asp.NETMVC项目中,我有4个模型类。我首先使用实体框架代码(自动迁移)。当我运行命令更新数据库时,我得到以下错误

在表“Tickets”上引入外键约束“FK_dbo.Tickets_dbo.Users_CreatedUserId”可能会导致循环或多个级联路径。指定“在删除时不执行操作”或“在更新时不执行操作”,或修改其他外键约束。 无法创建约束或索引。请参阅前面的错误

有什么问题

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

}
//公司类
公营公司
{
公共int Id{get;set;}
[所需长度(100)]
公共字符串标题{get;set;}
公共虚拟ICollection用户{get;set;}=new HashSet();
}
//用户类
公共类用户
{
公共int Id{get;set;}
[所需长度(50)]
公共字符串用户名{get;set;}
[所需长度(100)]
公共字符串全名{get;set;}
public int CompanyId{get;set;}
公共虚拟公司公司{get;set;}
}
//客票等级
公务舱票
{
公共int Id{get;set;}
[必需]
公共日期时间创建日期{get;set;}
[所需长度(100)]
公共字符串标题{get;set;}
公共布尔是封闭的{get;set;}
public int CreatedUserId{get;set;}
公共虚拟用户CreatedUser{get;set;}
公共虚拟ICollection消息{get;set;}=new HashSet();
}
//TicketMessage类
公共类TicketMessage
{
公共int Id{get;set;}
公共日期时间日期{get;set;}
[必需]
公共字符串消息{get;set;}
public int UserId{get;set;}
公共虚拟用户用户{get;set;}
public int TicketId{get;set;}
公共虚拟票证{get;set;}
}

如果删除一个模型(父模型)中的记录,它将删除子模型中与其相关的所有记录。在本例中,用户模型是具有多个票证和票证消息的父级,因此当您删除一个用户时,级联删除将同时删除所有用户票证和票证消息。当模型具有导航属性时,EF会自动指定外键。外键在模型之间创建关系,这意味着当“子”模型中的记录依赖于作为您试图删除的记录的主键存在的外键时,您不能删除一个模型中的记录

在您的情况下,如评论所述,您的用户模型与Ticket和TicketMessages具有一对多关系,您的Ticket模型与TicketMessages具有一对多关系。这意味着删除用户记录将删除所有TicketMessages和与该用户ID关联的票证,但(对于系统而言)具有该用户ID的TicketMessage也可能使用未被级联从该用户ID中删除的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>();
}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove();
modelBuilder.Conventions.Remove();
}
这两行分别删除了一对多和多对多级联删除约定。你可以把它们放在里面,也可以把它们取下来

您还可以使用以下方法删除单一级联删除关系:

modelBuilder.Entity<ParentEntity>()
.HasMany(p => p.Children)
.WithRequired()
.HasForeignKey(c => c.ParentEntityId)
.WillCascadeOnDelete(false);
modelBuilder.Entity()
.HasMany(p=>p.Children)
.WithRequired()
.HasForeignKey(c=>c.ParentEntityId)
.WillCascadeOnDelete(假);
我强烈推荐解决方案1,从TicketMessages模型中删除UserID,您的TicketMessages已经通过TicketMessages模型和Ticket模型之间的关系链接到UserID

编辑-我想你可能希望TicketMessages和User之间的关系表示编写消息的人,而此人不是创建票据的同一用户。如果是这种情况,我仍然建议删除与用户表的关系,而是使用一个字段,在该字段中,您可以填充您希望在创建票证消息时与该票证消息关联的任何用户信息,例如名称。或者,您仍然可以有一个UserID字段,但没有导航属性,从而删除外键关系。当您检索信息时,可以通过将此用户ID与用户表中的用户ID匹配来调用用户信息。

谢谢您的回答! 我用下面的代码解决了这个问题

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

这是因为表
用户
有许多
票证
和许多
票证消息
,同时
票证
有许多
票证消息
。是的,应该是这样的。因为,用户可以创建票证和票证消息。但如果删除一个特定的
用户
,SQL引擎不知道该怎么办。您应该按照字面意思执行:指定是在删除无操作时执行
,还是自定义
删除触发器