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

同一路由控制器中实现实体增删报DataReader已打开异常

问题描述

是否有方案可在同一路由控制器中同时实现实体的添加与删除操作?以下为实现点赞/取消点赞逻辑编写的C#接口,添加实体功能运行正常,但执行删除操作时抛出异常:

[HttpPost]
public async Task<ActionResult<Upvote>> AddRemoveUpvote(CreateUpvoteDTO upvoteDtO)
{
    if (_context.Upvotes == null)
    {
        return Problem("Entity set 'ApplicationDbContext.Upvotes'  is null.");
    }
    var upvote = _mapper.Map<Upvote>(upvoteDtO);
    foreach (var item in _context.Upvotes)
    {
        if (item.UserId == upvote.UserId)
        {
            _context.Upvotes.Remove(item);
            await _context.SaveChangesAsync();
            return Ok("Topic unliked");
        }
    }
    _context.Upvotes.Add(upvote);
    await _context.SaveChangesAsync();
    
    return Ok("Topic Liked");
}

触发的异常信息

System.InvalidOperationException: 已有与此连接关联的打开的DataReader,必须先将其关闭。
异常堆栈:Microsoft.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommand command)
异常堆栈:Microsoft.Data.SqlClient.SqlInternalConnection.BeginSqlTransaction(IsolationLevel iso, String transactionName, Boolean shouldReconnect)

错误原因
  • 直接遍历_context.Upvotes时,Entity Framework Core会使用DataReader以流式方式从数据库拉取数据,此时数据库连接被该DataReader独占,遍历未结束时调用SaveChangesAsync()会在同一个连接上发起新的数据库执行请求,直接触发连接占用异常。
  • 原有逻辑存在业务漏洞:仅通过UserId匹配点赞记录,未关联被点赞对象的唯一标识(如主题Id),会导致用户只要给任意内容点过赞,就会误删第一条匹配到的点赞记录,完全不符合点赞/取消点赞的业务预期。
  • 全表遍历查询性能极差,当点赞表数据量增长到一定规模后,接口会出现严重的响应超时问题。
修复方案
  • 放弃全表遍历写法,使用精准条件查询匹配的点赞记录,调用FirstOrDefaultAsync()提前执行查询,待DataReader释放、连接回收后再执行增删操作,从根源上避免连接占用问题。
  • 补全查询匹配条件,同时校验用户Id和被点赞对象Id,确保操作的是对应内容下的用户点赞记录。
  • 简化逻辑分支:查询到已存在的点赞记录则执行删除,不存在则新增,操作完成后统一保存变更即可。

修复后的参考代码:

[HttpPost]
public async Task<ActionResult> AddRemoveUpvote(CreateUpvoteDTO upvoteDto)
{
    if (_context.Upvotes == null)
    {
        return Problem("Entity set 'ApplicationDbContext.Upvotes' is null.");
    }
    // 注意将TopicId替换为你实际DTO中对应的被点赞对象字段名
    var existUpvote = await _context.Upvotes
        .FirstOrDefaultAsync(u => u.UserId == upvoteDto.UserId && u.TopicId == upvoteDto.TopicId);
    
    if (existUpvote != null)
    {
        _context.Upvotes.Remove(existUpvote);
        await _context.SaveChangesAsync();
        return Ok("Topic unliked");
    }

    var newUpvote = _mapper.Map<Upvote>(upvoteDto);
    _context.Upvotes.Add(newUpvote);
    await _context.SaveChangesAsync();
    return Ok("Topic Liked");
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 10:12:17