entity-framework - 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
那个默默地导致了这个?因为我目前没有设置配置?
解决方案
数据模型中的外键关系如下所示:
- 交易者 ->* 应用用户
- 交易者 ->* 应用用户
- 交易者联系历史 -> 交易者
- TraderContactHistory -> ApplicationUser
因此,如果您删除 ApplicationUser 条目,级联删除将删除所有 Trader 条目和指向它的所有 TraderContactHistory 条目。但是删除 Trader 条目反过来也会删除依赖的 TraderContactHistory 项目。所以你有两个从 ApplicationUser 到 TraderContactHistory 的级联删除路径:
- TraderContactHistory -> ApplicationUser
- TraderContactHistroy -> Trader -> ApplicationUser
而 MSSQL 不喜欢这样。我知道这有多烦人,相信我,因为我必须定期处理这个限制。
话虽如此,您在 TraderContactHistory 的关系中指定了“限制”,这应该可以解决问题。也许实际的架构没有正确反映这一点?
编辑:
我突然想到另一个直接的 Trader-ApplicationUser-relationship 可能是罪魁祸首。如果 Trader-AccountManager-dependency 设置为 OnDelete Cascade,您还将获得多个级联路径。
推荐阅读
- graph - TinkerPop/Graph:遍历边,然后按结果顶点和遍历边分组
- java - 误解main方法/“public static void main(String[] args)”的要点
- bash - 将字符串从串行复制到文件的 Bash 脚本
- sql - 加入时如何在多行中保留多个值?
- c - 用于学习的自定义 make 命令
- vba - VBA:将特定文件插入工作表上的预定位置
- arduino - 自定义 snprintf() 函数给出错误的输出
- php - Laravel 动态数据库连接
- adobe - 访问恢复文件 - InDesign
- django - django-import-export 分配当前用户