EF Core DeleteBehavior.Cascade可能会导致循环或多个级联路径

时间:2019-10-07 11:00:06

标签: entity-framework entity-framework-core

我有以下实体(为简洁起见,以下简称);

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的{​​{1}}是无声的原因吗?因为我目前没有设置配置?

1 个答案:

答案 0 :(得分:1)

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

  • 交易者-> * ApplicationUser
  • 交易者-> * ApplicationUser
  • TraderContactHistory->交易者
  • TraderContactHistory-> ApplicationUser

因此,如果删除ApplicationUser条目,则级联删除将删除所有Trader条目和所有指向该条目的TraderContactHistory条目。但是,删除操盘手条目将依次删除相应的操盘手条目。因此,您有两个从ApplicationUser到TraderContactHistory的级联删除路径:

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

,MSSQL不喜欢那样。相信我,我知道这很烦人,因为我必须定期处理此限制。

也就是说,您在TraderContactHistory的关系中指定了“ Restrict”,可以解决该问题。也许实际的模式不能正确反映出来?

修改:
在我看来,另一个直接的Trader-ApplicationUser-关系可能是罪魁祸首。如果将Trader-AccountManager-dependency设置为OnDelete Cascade,您还将获得多个级联路径。