Entity Framework Core 中的错误:由于重复的键值,无法跟踪实体类型“ProductOrder”的实例

问题描述 投票:0回答:1

我在开发 ASP.NET Core 应用程序时遇到了 Entity Framework Core 的问题。具体来说,我收到以下错误消息:

无法跟踪实体类型“ProductOrder”的实例,因为已跟踪具有相同键值 {'ProductID', 'OrderID', 'VariantID'} 的另一个实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。

这是我的代码中发生错误的相关部分:

[HttpPut("Update-Order/{orderId}")]
public async Task<ActionResult> UpdateOrder(int orderId, [FromBody] OrderRequestBodyDto orderRequestBody)
{
    try
    {
        // Code omitted for brevity

        // 2 - We delete the Products in the order
        await _orderService.DeleteProductOrderAsync(orderModel.productsOrder);

        // 3 - Recreate the Products in the order
        await _orderService.CreateOrderWithProductsAsync(orderId, orderRequestBody.products.ToList());

        // Code omitted for brevity
    }
    catch (Exception ex)
    {
        // Error handling code omitted for brevity
    }
}

我已确保我的服务注册为瞬态,如下所示:

// Order Services
builder.Services.AddTransient<IOrderRepository, SqlOrderRepo>();
builder.Services.AddTransient<IOrderValidationRepository, SqlOrderValidationRepo>();
builder.Services.AddTransient<OrderService>();

尽管如此设置,我仍然遇到上述错误。我不确定为什么上下文实例会导致此问题,特别是因为我使用的是具有短暂生命周期的服务。

任何有关如何解决此问题的见解或建议将不胜感激。

c# asp.net asp.net-core .net-core
1个回答
0
投票

我们没有看到这两个方法的代码,但我认为问题正在发生,因为您依赖于changetracker,并且您有两个独立的“工作单元”,您在其中执行数据库操作,并且在调用 SaveChanges 之前调用第二个方法,因此在第二个方法调用期间,changetracker 仍然记住相同的对象,这会导致问题。这个问题可以通过多种方式解决,但我建议将这些方法封装在一个事务中,并在这两个方法的末尾调用 SaveChanges ,这将确保原子性(无论如何,无论您当前的具体问题如何,您都希望拥有原子性)有)。

请注意,我假设 _orderService 可以访问相同的 DbContext。代码看起来像这样:

[HttpPut("Update-Order/{orderId}")]
public async Task<ActionResult> UpdateOrder(int orderId, [FromBody] OrderRequestBodyDto orderRequestBody)
{
    using (var transaction = _context.Database.BeginTransaction())
    {
        try
        {
            await _orderService.DeleteProductOrderAsync(orderModel.productsOrder);
            _context.SaveChanges();  
            await _orderService.CreateOrderWithProductsAsync(orderId, orderRequestBody.products.ToList());
            _context.SaveChanges();
            transaction.Commit();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error updating order with ID: {OrderId}", orderId);
            transaction.Rollback();
            return StatusCode(StatusCodes.Status500InternalServerError, "An error occurred while updating the order.");
        }
    }

    return Ok();
}
© www.soinside.com 2019 - 2024. All rights reserved.