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

如何正确删除数据库记录?Web API遇DataReader异常求助

问题原因与解决方案

错误原因

这个异常是因为EF延迟加载导致的多活跃DataReader冲突:当你遍历_dataContext.Urls这类IQueryable对象时,数据库连接的DataReader会保持打开状态以逐行读取数据;此时在循环内部执行_dataContext.ShortedUrls.FirstOrDefault()这类新查询,同一个连接上会存在两个活跃的DataReader,触发InvalidOperationException。

修复方案

1. 先将数据加载到内存,关闭DataReader

遍历前用ToListAsync()把查询结果加载到本地内存,避免延迟加载导致的DataReader持续打开。

2. 修复普通用户分支的逻辑错误

原代码在foreach循环内直接return Ok(),会导致仅删除第一条记录就返回,需将保存和返回逻辑移到循环外。

3. 利用导航属性简化操作

Url实体已关联ShortUrl导航属性,无需再查询ShortedUrls表,直接通过item.ShortUrl获取对应短链接。

4. 优化查询条件

用外键UserId代替实体比较UserCreatedBy == user,生成的SQL更高效,避免实体跟踪问题。

修改后的完整代码

[HttpDelete]
[Route("/DeleteUrls")]
public async Task<IActionResult> DeleteUrls(string userName)
{
    var user = await _dataContext.Users.FirstOrDefaultAsync(x => x.UserName == userName);
    if (user == null)
    {
        return BadRequest("No user with such Username");
    }

    switch (user.IsAdmin)
    {
        case true:
            // 加载所有Url到内存,关闭DataReader
            var allUrls = await _dataContext.Urls.Include(u => u.ShortUrl).ToListAsync();
            foreach (var url in allUrls)
            {
                // 利用导航属性直接获取ShortUrl
                if (url.ShortUrl != null)
                {
                    _dataContext.ShortedUrls.Remove(url.ShortUrl);
                }
                _dataContext.Urls.Remove(url);
            }
            await _dataContext.SaveChangesAsync();
            return Ok();
        
        case false:
            // 用UserId查询,加载当前用户的所有Url及关联的ShortUrl
            var userUrls = await _dataContext.Urls
                .Include(u => u.ShortUrl)
                .Where(x => x.UserId == user.Id)
                .ToListAsync();
            
            if (!userUrls.Any())
            {
                return BadRequest("No urls found for this user");
            }

            foreach (var url in userUrls)
            {
                if (url.ShortUrl != null)
                {
                    _dataContext.ShortedUrls.Remove(url.ShortUrl);
                }
                _dataContext.Urls.Remove(url);
            }
            await _dataContext.SaveChangesAsync();
            return Ok();
    }
}

可选补充:开启MARS(不推荐作为首选方案)

如果必须保持延迟加载,可以在数据库连接字符串中添加MultipleActiveResultSets=True,允许同一个连接上存在多个活跃的DataReader。但这种方式可能带来性能和资源占用问题,不如先加载到内存可控。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 16:25:14