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

C# 实体框架代码优先:循环或多个级联路径,c#,sql-server,entity-framework,ef-fluent-api,C#,Sql Server,Entity Framework,Ef Fluent Api,我有一个预订类,它有一个预订联系人(一个人)和一组导航属性(人),通过联接表链接到人中的另一组导航属性(预订)。如何生成针对预订联系人关系启用级联删除的预订表?当我将其从fluent API代码中删除(默认设置为启用级联删除)时,我从迁移中得到以下错误消息: 引入外键约束 表“BookingPeople”上的“FK_dbo.BookingPeople_dbo.People_PersonID” 可能导致循环或多个级联路径。指定删除编号 操作或更新时无操作,或修改其他外键 限制 无法创建约束或索引。

我有一个预订类,它有一个预订联系人(一个
)和一组导航属性(
),通过联接表链接到
中的另一组导航属性(
预订
)。如何生成针对预订联系人关系启用级联删除的
预订
表?当我将其从fluent API代码中删除(默认设置为启用级联删除)时,我从迁移中得到以下错误消息:

引入外键约束 表“BookingPeople”上的“FK_dbo.BookingPeople_dbo.People_PersonID” 可能导致循环或多个级联路径。指定删除编号 操作或更新时无操作,或修改其他外键 限制

无法创建约束或索引。请参阅前面的错误

modelBuilder.Entity()
.HasMany(s=>s.aBookings)
.WithRequired(s=>s.Contact)
.HasForeignKey(s=>s.ContactId);
modelBuilder.Entity()
.HasMany(t=>t.People)
.有很多(t=>t.预订)
.Map(m=>{
m、 ToTable(“预订人”);
m、 MapLeftKey(“BookingID”);
m、 MapRightKey(“PersonID”);
});

问题在于,您有多条级联删除路径,这些路径可能会导致尝试删除数据库中
BookingPeople
表中的同一行

您可以通过使用以下方法禁用一对多关系中的级联删除来避免这种不明确的删除路径:


如果依赖实体上的外键可为null,则Code First不会在关系上设置cascade delete,并且当主体被删除时,外键将设置为null。通过这种方式,您可以在
SaveChanges
方法中找到孤立项并将其删除

我不知道是否100%理解我的建议,因为我是新手,但是否可以创建单向一对多关系,因此,不需要删除导航属性,这会以某种方式修复它,还是删除路径仍然会混淆?即使您的单向一对多关系无法解决问题,您仍然会有多条路径,最终可能会尝试删除同一行。因此,我建议将一对多关系定义为可选关系,如果需要删除te孤立项,则覆盖SaveChanges方法。我想这个链接会帮助你更好地理解这个解决方案:谢谢,@octavioccl。这是一个非常全面的解释,有效地涵盖了我从其他线程中识别出的所有选项。本主题中的许多线程解决了如何禁用级联删除,但没有解决如果您确实需要该行为时如何解决该问题。我希望避免为每个关系编写手动删除方法,但这也解释了为什么存在这种限制,特别是从SQL Server的角度考虑时。这个答案在M2M关系中没有意义。如果在联接表中删除一个预订并级联删除相关的BookingPeople,则即使存在从人员到同一联接表的路径,也不应阻止您这样做。
 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");
   });
    modelBuilder.Entity<Booking>()
                .HasRequired(s => s.Contact)
                .WithMany(s => s.aBookings)
                .HasForeignKey(s => s.ContactId)
                .WillCascadeOnDelete(false);
     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>();
public override int SaveChanges()
{
    Bookings.Local
            .Where(r => r.ContactId == null)
            .ToList()
            .ForEach(r => Bookings.Remove(r));

    return base.SaveChanges();
 }