首页 文章

实体框架代码首先:循环或多个级联路径

提问于
浏览
4

我有一个Booking类,它有一个预订联系人( Person )和一组导航属性( People ),它们通过连接表链接到 Person 中的另一组导航属性( Bookings ) . 如何为预订联系人关系启用级联删除生成 Booking 表?当我将它从流畅的API代码中删除时(启用了级联删除的默认设置),我从迁移中收到以下错误消息:

在'BookingPeople'表上引入FOREIGN KEY约束'FK_dbo.BookingPeople_dbo.People_PersonID'可能会导致循环或多个级联路径 . 指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束 . 无法创建约束或索引 . 查看以前的错误 .

modelBuilder.Entity<Person>()
   .HasMany<Booking>(s => s.aBookings)
   .WithRequired(s => s.Contact)
   .HasForeignKey(s => s.ContactId); 


 modelBuilder.Entity<Booking>()
   .HasMany(t => t.People)
   .WithMany(t => t.Bookings)
   .Map(m => {
     m.ToTable("BookingPeople");
     m.MapLeftKey("BookingID");
     m.MapRightKey("PersonID");
   });

1 回答

  • 20

    问题是您有多个级联删除路径,可能会尝试删除DB中 BookingPeople 表中的同一行 .

    您可以通过使用Fluent API在一对多关系中禁用级联删除来避免此类不明确的删除路径:

    modelBuilder.Entity<Booking>()
                    .HasRequired(s => s.Contact)
                    .WithMany(s => s.aBookings)
                    .HasForeignKey(s => s.ContactId)
                    .WillCascadeOnDelete(false);
    

    或者通过将关系定义为可选(使用可为空的外键,但无法使用Fluent Api配置与级联删除的关系) .

    modelBuilder.Entity<Booking>()
                .HasOptional(s => s.Contact)
                .WithMany(s => s.aBookings)
                .HasForeignKey(s => s.ContactId);// ContactId is a nullable FK property
    

    此外,您可以使用以下命令删除级联删除约定:

    modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
    

    或者在多对多关系的情况下:

    modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
    

    如果你删除它时需要删除与 Person 相关的所有 Bookings ,我的建议是将一对多关系配置为可选,并覆盖 SaveChanges 方法:

    public override int SaveChanges()
    {
        Bookings.Local
                .Where(r => r.ContactId == null)
                .ToList()
                .ForEach(r => Bookings.Remove(r));
    
        return base.SaveChanges();
     }
    

    如果从属实体上的外键可以为空,则Code First不会在关系上设置级联删除,并且当删除主体时,外键将设置为 null . 这样,您可以在 SaveChanges 方法中找到孤儿并删除它们

相关问题