You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF Core对接SQL Server多级联路径报错的配置解决方法

我尝试在EF Core中使用SQL Server搭建支付模型,一笔支付包含转出方和转入方,双方均为用户(Actor实体)。我定义的Transaction类分别关联FromActor和ToActor两个属性,生成迁移更新数据库时失败,提示存在多条级联路径。我查到需要在数据库上下文的OnModelCreating方法中重写默认级联规则,但不清楚具体实现方式。我对EF和迁移操作比较陌生,此前仅跟着官方教程操作。

初始实体代码如下:

public class Actor
{
    public int ActorId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public List<Transaction> Transactions = new List<Transaction>();
}

public class Transaction
{
    public int TransactionId { get; set; }
    public DateTime TimestampUtc { get; set; }
    public decimal Amount { get; set; }
  
    public int FromActorId { get; set; }
    public Actor FromActor { get; set; }
    public int ToActorId { get; set; }
    public Actor ToActor { get; set; }
}

执行迁移时收到报错:

在Transactions表上引入外键约束'FK_Transactions_Actors_ToActorId'可能会导致循环或多条级联路径。请指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他外键约束。

请问我该如何在数据库上下文中配置解决该问题?还是需要调整我的领域模型设计?
我当前的OnModelCreating方法还是空的:

protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        ??
    }

最终解决方案

根据大家的建议,我最终的可用实现如下:

public class Actor
{
    public int ActorId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public virtual List<Transaction> FromTransactions { get; set; }
    public virtual List<Transaction> ToTransactions { get; set; }
}

public class Transaction
{
    public int TransactionId { get; set; }
    public DateTime TimestampUtc { get; set; }
    public double Amount { get; set; }
    
    public int FromActorId { get; set; }
    public virtual Actor FromActor { get; set; }
    public int ToActorId { get; set; }
    public virtual Actor ToActor { get; set; }
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Transaction>(entity =>
        {
            entity.HasOne(t => t.FromActor)
                .WithMany(a => a.FromTransactions)
                .HasForeignKey(t => t.FromActorId)
                .OnDelete(DeleteBehavior.NoAction)
                .HasConstraintName("FK_Transaction_Id_From_Actor");
            entity.HasOne(t => t.ToActor)
                .WithMany(a => a.ToTransactions)
                .HasForeignKey(t => t.ToActorId)
                .OnDelete(DeleteBehavior.NoAction)
                .HasConstraintName("FK_Transaction_Id_To_Actor");
        });

        Seed(modelBuilder);
    }

    private void Seed(ModelBuilder modelBuilder)
    {
        using (var reader = new StreamReader("Data/Actors.csv"))
        using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
        {
            var actors = csv.GetRecords<Actor>();
            modelBuilder.Entity<Actor>().HasData(actors.ToArray());
        }
    }

protected async Task<Transaction> SaveTransactionAsync()
    {
        using (var context = contextFactory.CreateDbContext())
        {
            var transaction = new Transaction()
            {
              TimestampUtc = DateTime.UtcNow,
              Amount = 20.45,   // 为演示硬编码
              FromActorId = 1,  // 为演示硬编码,使用Actor种子文件中的id
              ToActorId = 2,    // 为演示硬编码,使用Actor种子文件中的id
            };
            context.Add(transaction);
            await context.SaveChangesAsync();
            await context.Entry(transaction).Reference(t => t.FromActor).LoadAsync();
            await context.Entry(transaction).Reference(t => t.ToActor).LoadAsync();
            logger.LogDebug("Saved transaction to database.");
            return transaction;
        }
        
    }

经验总结

除了禁用级联删除外,我得到的主要经验是必须为Actor实体引入两个集合(转出交易集合和转入交易集合)。另外保存Transaction时不能直接设置FromActor和ToActor导航属性,只能设置对应的id,直接设置对象会导致保存交易时尝试向Actors表插入新数据,这点不符合直觉。


内容的提问来源于stack exchange,提问作者Heems

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 12:39:03