【问题标题】:Entity Framework Code first: cycles or multiple cascade paths实体框架代码优先:循环或多个级联路径
【发布时间】:2015-05-17 16:44:47
【问题描述】:

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

引入 FOREIGN KEY 约束 表“BookingPeople”上的“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");
   });

【问题讨论】:

    标签: c# sql-server entity-framework ef-fluent-api


    【解决方案1】:

    问题是您有多个级联删除路径,可能会尝试删除 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方法中找到孤儿并删除

    【讨论】:

    • 我不知道我是否 100% 理解我的建议,因为我是新手,但是否可以创建单向的一对多关系,这样就不需要 aBookings导航属性,会以某种方式修复它还是删除路径仍然会混淆?
    • 即使你有一个无法解决问题的单向一对多关系,你仍然会有多个路径可能会试图删除同一行。出于这个原因,我建议将一对多关系定义为可选的,如果您需要删除 te orphans 然后覆盖 SaveChanges 方法。我认为这个链接可以帮助你更好地理解这个解决方案:Deleting orphans with Entity Framework
    • 谢谢你,@octavioccl。这是一个非常全面的解释,有效地涵盖了我能够从其他线程中识别的所有选项。关于该主题的许多主题讨论了如何禁用级联删除,而不是如何解决问题,如果您确实需要该行为。我希望避免为每个关系编写手动删除方法,但为什么存在这种限制也是有道理的,尤其是从 SQL Server 的角度考虑它时。
    • 这个答案在 M2M 关系的情况下没有意义。如果您在连接表中删除一个 Booking 并级联删除相关的 BookingPeople,即使存在从 People 到同一个连接表的路径,也不应该阻止您这样做。
    猜你喜欢
    • 2021-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-18
    • 1970-01-01
    相关资源
    最近更新 更多