EF Core 中多对多关系的级联参照完整性约束

Cascading Referential Integrity Constraints for many to many relationships in EF Core

我将 EF Core 3.1.5 与 Asp.Net Core 3.1 一起使用。当我尝试添加迁移时,出现下一个错误:

Microsoft.Data.SqlClient.SqlException (0x80131904): Introducing FOREIGN KEY constraint 'FK_PhotoDevice_Device_DeviceId' on table 'PhotoDevice' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

我有下一个实体和配置:

public class User {
   [Key]
   public long Id { get; set; }
   // Fields
   public IEnumerable<Device> Devices { get; set; }
   public IEnumerable<Photo> Photos { get; set; }
}

public class Photo {
   [Key]
   public long Id { get; set; }
   // Fields
   [ForeignKey("User")]
   public long UserRef { get; set; }
   public User User { get; set; }
   public IEnumerable<PhotoDevice> PhotoDevices { get; set; }
}

public class Device {
   [Key]
   public long Id { get; set; }
   // Fields
   [ForeignKey("User")]
   public long UserRef { get; set; }
   public User User { get; set; }
   public IEnumerable<PhotoDevice> PhotoDevices { get; set; }
}

public class PhotoDevice {
{
   public long? PhotoRef { get; set; }
   public Photo Photo { get; set; }

   public long? DeviceRef { get; set; }
   public Device Device { get; set; }
}

public class AppDbContext : DbContext
{
   public DbSet<User> Users { get; set; }
   public DbSet<Photo> Photos { get; set; }
   public DbSet<Device> Devices { get; set; }
   public DbSet<PhotoDevice> PhotoDevices { get; set; }
   public AppDbContext(DbContextOptions<AppDbContext> options)
   : base(options)
   {
      Database.Migrate();
   }

   protected override void OnModelCreating(ModelBuilder builder)
   {
      builder.Entity<Photo>()
         .HasOne(photo => photo.User)
         .WithMany(user => user.Photos);

      builder.Entity<Device>()
         .HasOne(device => device.User)
         .WithMany(user => user.Devices);

      builder.Entity<PhotoDevice>()
         .HasKey(bc => new { bc.PhotoRef, bc.DeviceRef });
      builder.Entity<PhotoDevice>()
         .HasOne(bc => bc.Photo)
         .WithMany(b => b.PhotoDevices)
         .HasForeignKey(bc => bc.PhotoRef);
      builder.Entity<PhotoDevice>()
         .HasOne(bc => bc.Device)
         .WithMany(c => c.PhotoDevices)
         .HasForeignKey(bc => bc.DeviceRef);
   }
}

我发现问题与级联连接的不唯一性有关。但现在我很困惑。因为我认为这个结构是必要的,我不想放弃任何 FK。如果我需要下一个逻辑,我该如何解决问题:

您不需要删除任何外键。只需使用 OnDelete(DeleteBehavior) 明确指定您需要哪种级联行为。

例如,以下将导致您的模型创建成功,但对于您的实际应用程序,您需要自己决定在何处以及如何打破级联

builder.Entity<PhotoDevice>()
    .HasOne(bc => bc.Photo)
    .WithMany(b => b.PhotoDevices)
    .HasForeignKey(bc => bc.PhotoRef)
    .OnDelete(DeleteBehavior.Restrict); // <-- define cascading behavior

有关详细信息,请参阅 Relationships: Cascade delete and Cascade Delete

这不是EF Core,而是SQL服务器限制(因此SQL服务器也会抛出异常)

这里有进一步的资源,处理这个限制并展示如何解决它,通过使用INSTEAD OF触发器,如果​​打破级联不是一个选项你可以忍受:

lauxjpn说的是对的,但是请注意,添加的时候.OnDelete(DeleteBehavior.Restrict); 之后到你的context,请记得删除你之前的所有migrations,不然还是会报错。