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

EF Core Db-first模式下不使用级联删除如何删除父子关联记录

EF Core DbFirst模式下多关联表批量删除外键冲突解决方案

采用Db-first开发模式。
我对EF并不陌生,但整理了这个示例,因为我不确定删除操作中如何处理复杂的父子外键(FK)关联场景。我当前实际开发的代码涉及10~12张存在外键关联的互相关联表,需要批量删除其中一批数据,因此这个示例很有代表性。

删除记录时,执行顺序是否重要?在TSQL中确实存在顺序要求(我原本认为需要先删除父记录再删除子记录)。

如下示例代码运行后我得到了下方报错,显然是因为Book表存在指向Warehouse表的外键:
注意:

{"DELETE语句与REFERENCE约束"FK_Book_Warehouse"冲突。该冲突发生于数据库"AdHoc",表"dbo.Book",列"WarehouseKey"。
语句已终止。"}

其他说明

  • 如果每个关联实体都需要基于独立的查询获取,级联删除无法生效。
  • 需要使用join查询,因为要删除的记录超过10万条,使用where/contains的写法会过于混乱。
  • 更希望所有操作在一次SaveChanges中完成,以便使用TransactionScope将所有操作包裹在同一个事务中。
  • 我采用Db-first工作流,使用EF Core POCO generator反向工程工具生成模型,因此不建议手动修改生成的模型类,因为表结构变更重新生成模型时手动修改的内容会丢失。

报错示例代码

public bool DeleteComplex()
{
    bool retval = false;

    string bookfilter = "Big Fish";

    // 根据书名获取要删除的作者列表
    List<Author> AuthorList = (from a in ctx.Book 
                               join b in ctx.Author on a.AuthorKey equals b.Id where a.Title.Contains(bookfilter) select b).ToList();
    ctx.Author.RemoveRange(AuthorList);

    // 根据书名获取要删除的仓库列表
    List<Warehouse> WarehouseList = (from a in ctx.Book
                                     join b in ctx.Warehouse on a.WarehouseKey equals b.Id
                                     where a.Title.Contains(bookfilter)
                                     select b).ToList();
    ctx.Warehouse.RemoveRange(WarehouseList);

    // 根据书名删除书籍
    List<Book> BookList = (from a in ctx.Book where a.Title.Contains(bookfilter) select a).ToList();
    ctx.Book.RemoveRange(BookList);
    int results = ctx.SaveChanges();
    if(results > 0)
    {
        retval = true;
    }

    return retval;
}

[更新:可正常运行的最终代码]

调整后的差异在于:先删除子记录(或查询得到的子记录集合)后调用SaveChanges持久化,再删除依赖的父集合后调用SaveChanges。同时将所有操作包裹在事务中,可以实现全部成功或全部回滚的原子性。

public bool DeleteComplex()
{
    bool retval = false;

    string bookfilter = "Big Fish";

    // 根据书名获取要删除的书籍列表
    List<Book> BookList = (from a in ctx.Book where a.Title.Contains(bookfilter) select a).ToList();


    // 根据书名获取要删除的作者列表
    List<Author> AuthorList = (from a in ctx.Book
                               join b in ctx.Author on a.AuthorKey equals b.Id
                               where a.Title.Contains(bookfilter)
                               select b).ToList();

    // 根据书名获取要删除的仓库列表
    List<Warehouse> WarehouseList = (from a in ctx.Book
                                     join b in ctx.Warehouse on a.WarehouseKey equals b.Id
                                     where a.Title.Contains(bookfilter)
                                     select b).ToList();

    // 先删除子表记录并持久化
    ctx.Book.RemoveRange(BookList);
    int results = ctx.SaveChanges();
    if (results > 0)
    {
        retval = true;
    }


    // 再删除父表依赖记录
    ctx.Author.RemoveRange(AuthorList);
    ctx.Warehouse.RemoveRange(WarehouseList);

    results = ctx.SaveChanges();
    if (results > 0)
    {
        retval = true;
    }
    else
    {
        retval = false;
    }

    return retval;
}

// 事务包裹调用示例
try
{
    // 测试代码
    //var results = service.GetDoTest();
    //Console.WriteLine(results);
    using (TransactionScope transaction = new TransactionScope())
    {
        var results2 = service.DeleteComplex();
        Console.WriteLine(results2);

        transaction.Complete();
    }
}
catch(Exception ex)
{
    logger.Error($"Ran into error: {ex.ToString()}");
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 23:54:07