【问题标题】:Entity Framework Core: How to solve Introducing FOREIGN KEY constraint may cause cycles or multiple cascade pathsEntity Framework Core:如何解决引入 FOREIGN KEY 约束可能导致循环或多个级联路径
【发布时间】:2017-06-04 16:38:24
【问题描述】:

我正在使用带有 Code First 方法的 Entity Framework Core,但在更新数据库时收到以下错误:

在表“AnEventUsers”上引入 FOREIGN KEY 约束“FK_AnEventUsers_Users_UserId”可能会导致循环或多个级联路径。指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。 无法创建约束或索引。请参阅以前的错误。

我的实体是这些:

public class AnEvent
{
    public int AnEventId { get; set; }
    public DateTime Time { get; set; }
    public Gender Gender { get; set; }
    public int Duration { get; set; }
    public Category Category { get; set; }
    public int MinParticipants { get; set; }
    public int MaxParticipants { get; set; }
    public string Description { get; set; }
    public Status EventStatus { get; set; }
    public int MinAge { get; set; }
    public int MaxAge { get; set; }
    public double Longitude { get; set; }
    public double Latitude { get; set; }

    public ICollection<AnEventUser> AnEventUsers { get; set; }

    public int UserId { get; set; }
    public User User { get; set; }
}


public class User
{
    public int UserId { get; set; }
    public int Age { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Gender Gender { get; set; }
    public double Rating { get; set; }

    public ICollection<AnEventUser> AnEventUsers { get; set; }
}

public class AnEventUser
{
    public int AnEventId { get; set; }
    public AnEvent AnEvent { get; set; }

    public int UserId { get; set; }
    public User User { get; set; }

}

public class ApplicationDbContext:DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options):base(options)
    { }


    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<AnEventUser>()
            .HasOne(u => u.User).WithMany(u => u.AnEventUsers).IsRequired().OnDelete(DeleteBehavior.Restrict);


        modelBuilder.Entity<AnEventUser>()
            .HasKey(t => new { t.AnEventId, t.UserId });

        modelBuilder.Entity<AnEventUser>()
            .HasOne(pt => pt.AnEvent)
            .WithMany(p => p.AnEventUsers)
            .HasForeignKey(pt => pt.AnEventId);

        modelBuilder.Entity<AnEventUser>()
            .HasOne(eu => eu.User)
            .WithMany(e => e.AnEventUsers)
            .HasForeignKey(eu => eu.UserId);

    }

    public DbSet<AnEvent> Events { get; set; }
    public DbSet<User> Users { get; set; }
    public DbSet<AnEventUser> AnEventUsers { get; set; }
}

我认为的问题是,如果我们删除用户,则对 AnEvent 的引用将被删除,对 AnEventUser 的引用也将被删除,因为 AnEvent 中也有对 AnEventUser 的引用,我们得到了级联路径。但是我删除了从 User 到 AnEventUser 的删除级联:

 modelBuilder.Entity<AnEventUser>()
        .HasOne(u => u.User).WithMany(u => u.AnEventUsers).IsRequired().OnDelete(DeleteBehavior.Restrict);

但是错误没有得到解决,有没有人看到有什么问题?谢谢!

【问题讨论】:

    标签: entity-framework foreign-keys entity-framework-core


    【解决方案1】:

    OnModelCreating 的示例代码中,您已经声明了两次modelBuilder.Entity&lt;AnEventUser&gt;().HasOne(e =&gt; e.User)...:在方法的开头和结尾。

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<AnEventUser>()       // THIS IS FIRST
            .HasOne(u => u.User).WithMany(u => u.AnEventUsers).IsRequired().OnDelete(DeleteBehavior.Restrict);
    
    
        modelBuilder.Entity<AnEventUser>()
            .HasKey(t => new { t.AnEventId, t.UserId });
    
        modelBuilder.Entity<AnEventUser>()
            .HasOne(pt => pt.AnEvent)
            .WithMany(p => p.AnEventUsers)
            .HasForeignKey(pt => pt.AnEventId);
    
        modelBuilder.Entity<AnEventUser>()       // THIS IS SECOND.
            .HasOne(eu => eu.User)               // THIS LINES
            .WithMany(e => e.AnEventUsers)       //   SHOULD BE
            .HasForeignKey(eu => eu.UserId);     //   REMOVED
    
    }
    

    第二次调用优先。删除它。

    【讨论】:

    • 我删除了第二部分,但它仍然不起作用。第二部分说明什么是外键。否则如何定义 AnEvent 和 User 之间的多对多关系。因此,删除用户将删除具有用户外键的 AnEvent。 AnEventUser 对 AnEvent 和 User 都有外键,我认为这是导致级联删除的问题。如何正确定义 Fluent API?
    • 您使用OnDelete(DeleteBehavior.Restrict); 的第一部分正确取消了此关系的级联删除。如果你想配置更多东西(HasForreignKey) - 把它放在这里,不要再写同样的HasOne(...),它会完全取消第一个。再次检查并发布新代码(没有重复但仍然产生错误)。
    • 嗯。您是否在更改之后、Update-Database 之前使用 Remove-MigrationAdd-Migration 重新创建迁移?更新数据库只是应用已经存在的(旧的)迁移。
    • 我添加了 OnDelete(DeleteBehavior.Restrict);它有效,但我仍然不知道它到底做了什么..
    • @Bharat,它将ON DELETE NO ACTION 设置为参照完整性约束。另外,请阅读此处的“多个级联操作”。
    【解决方案2】:

    这是我从德米特里的回答中所做的,

    它对我有用。

    类:

    public class EnviornmentControls
    {
        public int Id { get; set; }
        ...
    
        public virtual Environment Environment { get; set; }
    }
    

    这是映射

    public EnviornmentControlsMap(EntityTypeBuilder<EnviornmentControls> entity)
    {
            entity.HasKey(m => m.Id);           
    
            entity.HasOne(m => m.Environment)
                .WithMany(m => m.EnviornmentControls)
                .HasForeignKey(m => m.EnvironmentID)
                .OnDelete(DeleteBehavior.Restrict); // added OnDelete to avoid sercular reference 
    }
    

    【讨论】:

    • 你在哪里添加了EnviornmentControlsMap 方法?这是在 EnviornmentControls 模型上,还是在您的 DbContext 类上,还是在其他地方?
    • 这是我自己在 Environment 类中添加的反向集合。
    【解决方案3】:

    这些解决方案不适用于我的情况,但我找到了一种方法。我还不确定它是否安全,但删除时会发生一些事情。所以我修改了生成的迁移文件而不是覆盖。

    onDelete: ReferentialAction.Cascade
    

    我这样做的原因是因为上面提到的所有覆盖都对我不起作用,所以我手动删除了与删除级联相关的代码。

    只需检查错误中提到的具体关系,以便您直接进行。

    希望这对一些和我有同样问题的人有所帮助。

    【讨论】:

      【解决方案4】:
      public Guid? UsuarioId { get; set; }
      
      builder.Entity<Orcamentacao>()
             .HasOne(x => x.Usuario)
             .WithMany(x => x.Orcamentacaos)
             .OnDelete(DeleteBehavior.Restrict)
             .IsRequired(false)
             .HasForeignKey(x => x.UsuarioId);
      

      【讨论】:

      • 在 Stack Overflow 上不鼓励仅使用代码的答案,因为它们没有解释它如何解决问题。请编辑您的答案以解释此代码的作用以及它如何回答问题,以便它对 OP 以及其他有类似问题的用户有用
      猜你喜欢
      • 2021-08-24
      • 2021-10-06
      • 2011-05-08
      • 2013-10-22
      • 2019-10-20
      • 2018-12-14
      相关资源
      最近更新 更多