首页 > 解决方案 > EF Core DeleteBehavior.Cascade 可能会导致循环或多个级联路径

问题描述

我有以下实体(为简洁起见减少了);

public class Trader : AuditableEntity
{
    public int? UserId { get; set; }
    public ApplicationUser User { get; set; }

    public int? AccountManagerId { get; set; }
    public ApplicationUser AccountManager { get; set; }

    public List<TraderContactHistory> ContactHistory { get; set; }
}

public class ApplicationUser : IdentityUser<int>, IEntity
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Level { get; set; }

    public DateTime JoinDate { get; set; }
    public DateTime? LastLogin { get; set; }

    public ApplicationUserImage ProfileImage { get; set; }
}

为了完整起见TraderContactHistory,如下所示;

public class TraderContactHistory : Entity
{
    public Trader Trader { get; set; }
    public DateTime ContactDate { get; set; }
    public ApplicationUser ContactedBy { get; set; }
    public bool RequestedCallbackLater { get; set; }
    public string Notes { get; set; }
}

现在添加更改约束后;

public override void Configure(EntityTypeBuilder<Trader> entity)
{
    entity.HasOne(x => x.User)
        .WithOne()
        .HasForeignKey<Trader>(x => x.UserId)
        .OnDelete(DeleteBehavior.Restrict);
}

到以下(因为我们现在需要在删除交易者时清除相关用户);

public override void Configure(EntityTypeBuilder<Trader> entity)
{
    entity.HasOne(x => x.User)
        .WithOne()
        .HasForeignKey<Trader>(x => x.UserId)
        .OnDelete(DeleteBehavior.Cascade);

    entity.HasOne(x => x.AccountManager)
        .WithMany()
        .HasForeignKey(x => x.AccountManagerId)
        .OnDelete(DeleteBehavior.SetNull);
}

为了完整起见,TraderContactHistory配置是;

    public override void Configure(EntityTypeBuilder<TraderContactHistory> entity)
    {
        entity.HasKey(x => x.Id);

        entity.HasOne(x => x.Trader)
            .WithMany(x => x.ContactHistory)
            .OnDelete(DeleteBehavior.Restrict);

        entity.HasOne(x => x.ContactedBy)
            .WithMany()
            .OnDelete(DeleteBehavior.Restrict);

    }

生成以下迁移;

    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropForeignKey(
            name: "FK_Traders_AspNetUsers_UserId",
            schema: "Bemfeito",
            table: "Traders");

        migrationBuilder.AddForeignKey(
            name: "FK_Traders_AspNetUsers_UserId",
            schema: "Bemfeito",
            table: "Traders",
            column: "UserId",
            principalSchema: "Bemfeito",
            principalTable: "AspNetUsers",
            principalColumn: "Id",
            onDelete: ReferentialAction.Cascade);
    }

这在我运行时导致以下错误update-database(我正在运行 MSSQL 数据库);

System.Data.SqlClient.SqlException (0x80131904):在表 'Traders' 上引入 FOREIGN KEY 约束 'FK_Traders_AspNetUsers_UserId' 可能会导致循环或多个级联路径。指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。

谁能看到为什么会产生这个?可能是TraderContactHistory链接到Trader那个默默地导致了这个?因为我目前没有设置配置?

标签: entity-frameworkentity-framework-core

解决方案


数据模型中的外键关系如下所示:

  • 交易者 ->* 应用用户
  • 交易者 ->* 应用用户
  • 交易者联系历史 -> 交易者
  • TraderContactHistory -> ApplicationUser

因此,如果您删除 ApplicationUser 条目,级联删除将删除所有 Trader 条目和指向它的所有 TraderContactHistory 条目。但是删除 Trader 条目反过来也会删除依赖的 TraderContactHistory 项目。所以你有两个从 ApplicationUser 到 TraderContactHistory 的级联删除路径:

  • TraderContactHistory -> ApplicationUser
  • TraderContactHistroy -> Trader -> ApplicationUser

而 MSSQL 不喜欢这样。我知道这有多烦人,相信我,因为我必须定期处理这个限制。

话虽如此,您在 TraderContactHistory 的关系中指定了“限制”,这应该可以解决问题。也许实际的架构没有正确反映这一点?

编辑:
我突然想到另一个直接的 Trader-ApplicationUser-relationship 可能是罪魁祸首。如果 Trader-AccountManager-dependency 设置为 OnDelete Cascade,您还将获得多个级联路径。


推荐阅读