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

优化C# API中依赖父对象的多对象批量删除逻辑

优化学生关联成绩删除性能并保留日志记录的方案

核心优化思路

原来的逐条删除+日志记录会产生N次成绩删除请求 + N次日志插入请求(N为成绩数量),这是性能瓶颈的根源。优化方向是:

  • 一次性获取所有待删除的成绩数据(1次DB查询)
  • 批量生成并插入操作日志(可选:1次DB批量插入)
  • 批量删除成绩记录(1次DB批量操作)
  • 最后删除学生(1次DB操作)
    全程通过事务保证数据一致性。

具体实现代码

1. 修改辅助函数,实现批量处理+日志记录

假设你使用的是EF Core 7+(支持ExecuteDelete),可以这样重构:

public async Task DeleteStudentGradeAsync(int studentId)
{
    // 1. 一次性查询该学生所有成绩(仅查询日志需要的字段,减少内存开销)
    var gradesToDelete = await _dbContext.Grades
        .Where(g => g.StudentId == studentId)
        .Select(g => new { g.Id, g.Subject, g.Score, g.CreatedDate })
        .ToListAsync();

    if (!gradesToDelete.Any())
        return;

    // 2. 批量生成日志记录(先收集到列表,再批量插入)
    var historyLogs = new List<HistoryGrade>();
    foreach (var grade in gradesToDelete)
    {
        historyLogs.Add(new HistoryGrade
        {
            GradeId = grade.Id,
            OperationType = "Delete",
            Subject = grade.Subject,
            Score = grade.Score,
            OperationTime = DateTime.UtcNow
            // 补充其他日志所需字段
        });
    }

    // 批量插入日志(1次DB操作)
    _dbContext.HistoryGrades.AddRange(historyLogs);
    await _dbContext.SaveChangesAsync();

    // 3. 批量删除成绩(1次DB操作,直接生成DELETE SQL,不加载完整实体)
    await _dbContext.Grades
        .Where(g => g.StudentId == studentId)
        .ExecuteDeleteAsync();
}

2. 整合到主删除函数并添加事务

确保整个删除流程在事务中执行,避免部分操作失败导致数据不一致:

public async Task DeleteStudentAsync(int studentId)
{
    using var transaction = await _dbContext.Database.BeginTransactionAsync();
    try
    {
        // 先处理成绩删除和日志记录
        await DeleteStudentGradeAsync(studentId);

        // 删除学生
        var student = await _dbContext.Students.FindAsync(studentId);
        if (student != null)
        {
            _dbContext.Students.Remove(student);
            await _dbContext.SaveChangesAsync();
        }

        await transaction.CommitAsync();
    }
    catch (Exception)
    {
        await transaction.RollbackAsync();
        throw; // 抛出异常交由上层处理
    }
}

额外适配与优化

  • 如果你的EF Core版本低于7,无法使用ExecuteDelete,可以用以下方式批量删除(性能略逊但远优于逐条删除):
    _dbContext.Grades.RemoveRange(_dbContext.Grades.Where(g => g.StudentId == studentId));
    await _dbContext.SaveChangesAsync();
    
  • 若使用EF Core 8+,日志插入也可以用ExecuteInsert进一步优化,直接生成批量INSERT SQL:
    await _dbContext.HistoryGrades
        .ExecuteInsertAsync(
            from g in gradesToDelete
            select new HistoryGrade
            {
                GradeId = g.Id,
                OperationType = "Delete",
                Subject = g.Subject,
                Score = g.Score,
                OperationTime = DateTime.UtcNow
            });
    

性能对比

原来10条成绩需要20次DB调用(10次删成绩+10次插日志),优化后最多仅需4次DB调用(1次查成绩+1次插日志+1次删成绩+1次删学生),性能提升显著。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 05:10:23