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

C# API中HTTP DELETE返回200却未删除数据库数据的问题求助

C# API DELETE返回200但未删除数据库数据问题排查

问题描述

开发C# API应用时,GET方法正常工作,但DELETE方法返回200成功状态码,却没有删除数据库中的对应数据。采用了工作单元(Unit of Work)和仓储(Repository)模式。

排查与解决方案

1. 确认工作单元CommitAsync()的实现

工作单元的CommitAsync()是提交数据库修改的核心,必须确保它正确调用了EF Core的SaveChangesAsync()。当前提供的UnitOfWork类未包含该方法的实现,正确实现如下:

public async Task CommitAsync()
{
    await _db.SaveChangesAsync();
}

如果CommitAsync()未实现或未正确调用SaveChangesAsync(),即使调用了该方法,修改也不会同步到数据库。

2. 检查是否获取到待删除的实体

如果OrderRepository.Get(id)返回null,EF Core的Remove(null)不会执行任何删除操作,且不会抛出异常,导致接口返回200但无实际修改。需在Delete方法中增加空值判断:

public async Task Delete(int id)
{
    try
    {
        var order = await _unitOfWork.OrderRepository.Get(id);
        if (order == null)
        {
            throw new KeyNotFoundException($"ID为{id}的订单不存在");
        }
        _unitOfWork.OrderRepository.Delete(order);
        await _unitOfWork.CommitAsync();
    }
    catch (Exception e)
    {
        await _unitOfWork.RollbackAsync();
        throw;
    }
}

同时控制器可根据异常类型返回404状态码,更准确反馈结果:

[HttpDelete("{id}")]
public async Task<ActionResult> RemoveOrder(int id)
{
    try
    {
        await _orderService.Delete(id);
        return Ok();
    }
    catch (KeyNotFoundException ex)
    {
        return NotFound(ex.Message);
    }
    catch (Exception ex)
    {
        return StatusCode(500);
    }
}

3. 验证仓储Get(id)方法的正确性

通用仓储的Get(id)需正确从数据库查询实体,比如使用EF Core的FindAsync方法:

public async Task<T> Get(int id)
{
    return await _db.Set<T>().FindAsync(id);
}

如果Get方法的查询逻辑错误(如使用同步方法未等待、查询条件错误),会导致无法获取实体,进而无法执行删除。

4. 检查DbContext的依赖注入生命周期

确保NorthwindContext被注册为Scoped生命周期,避免单例上下文导致的状态不一致:

services.AddDbContext<NorthwindContext>(options => 
    options.UseSqlServer(Configuration.GetConnectionString("Northwind")),
    ServiceLifetime.Scoped);

若上下文为单例,多个请求共用同一实例可能导致修改未及时提交。

5. 排查事务或拦截器影响

如果存在全局事务拦截器、自定义SaveChanges拦截器,需确认它们未阻止删除操作的提交。


提供的相关代码

控制器代码

private readonly IOrderService _orderService;

public OrdersController(IOrderService orderService)
{
    _orderService = orderService;         
}

[HttpDelete("{id}")]
public async Task<ActionResult> RemoveOrder(int id)
{
    try
    {
        await _orderService.Delete(id);
        return StatusCode(200);
    }
    catch (Exception ex)
    {
        return StatusCode(500);
    }
}

服务接口

public interface IOrderService
{
    Task<Order> Get(int id);
    Task Add(Order order);
    Task Delete(int id);
    Task Update(int id, Order order);

    Task<IEnumerable<Order>> GetAllOrdersAsync();
    Task<IEnumerable<OrderDTO>> GetOrdersToCityAsync(string cityName);

    Task<OrderDTO> GetEmployeeOrdersToCountryAsync
    (
        string countryName, string employeeLastName
    );
}

服务实现类

public class OrderService : IOrderService
{
    private readonly IUnitOfWork _unitOfWork;
    public OrderService(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }
    public async Task Delete(int id)
    {
        try
        {
            var order = await _unitOfWork.OrderRepository.Get(id);
            _unitOfWork.OrderRepository.Delete(order);
            await _unitOfWork.CommitAsync();
        }
        catch (Exception e)
        {
            await _unitOfWork.RollbackAsync();
            throw;
        }
    }
}

工作单元类

public class UnitOfWork : IUnitOfWork
{
    private readonly NorthwindContext _db;
    private List<object> _customRepositories = new List<object>();
    private IProductRepository _productRepository;
    private IOrderRepository _orderRepository;
    public UnitOfWork(
        NorthwindContext db, 
        IProductRepository ProductRepository,
        IOrderRepository orderRepository
        )
    { 
        _db = db;
        _productRepository = ProductRepository;
        _orderRepository = orderRepository;
    }
}

工作单元接口

public interface IUnitOfWork
{
    IProductRepository ProductRepository { get; }

    IOrderRepository OrderRepository { get; }
    Task CommitAsync();
    Task RollbackAsync();
}

订单仓储接口

public interface IOrderRepository : IGenericRepository<Order>
{
    Task<IEnumerable<OrderDTO>> GetOrdersToCityAsync(string cityName);

    Task<OrderDTO> GetEmployeeOrdersToCountryAsync
        (
            string countryName, string employeeLastName
        );
}

订单仓储实现类

public class OrderRepository : GenericRepository<Order>, IOrderRepository
{
    private readonly NorthwindContext _northwindContext;
    public OrderRepository(NorthwindContext db) : base(db)
    {
        _northwindContext = db;
    }
}

通用仓储类

public class GenericRepository<T> : IGenericRepository<T> where T : class
{
    protected readonly NorthwindContext _db;

    public GenericRepository(NorthwindContext db)
    {
        _db = db;
    }

    public void Delete(T entity)
    {
        _db.Set<T>().Remove(entity);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 01:00:55