尝试更新图形时出现异常。我使用Automapper将DTO映射到我的实体,然后在执行更新操作之前检查数据库中是否已存在我的对象。
当我致电dbContext.Update
时,出现此异常
无法跟踪实体类型“ Order”的实例,因为已经跟踪了另一个具有相同“ {'OrderId'}”键值的实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。考虑使用'DbContextOptionsBuilder.EnableSensitiveDataLogging'查看冲突的键值。'
我的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AutoMapper;
using EFCoreIssue;
using EFCoreIssue.Dtos;
using EFCoreIssue.Models;
using Microsoft.EntityFrameworkCore;
using Xunit;
namespace EFCoreIssue_Tests
{
public class OrdersTests
{
private readonly OrderRepository _orderRepository;
public OrdersTests()
{
_orderRepository = new OrderRepository(new OrdersDbContext());
Mapper.Initialize(cfg => cfg.CreateMap<OrderDto, Order>());
}
[Fact]
public async void Should_Update_Customer_Successfully()
{
//Arrange
var order = new Order
{
Description = "Test Order",
OrderLines = new List<OrderLine>
{
new OrderLine {ProductId = 1, Quantity = 1}
}
};
using (var dbContext = new OrdersDbContext())
{
dbContext.Orders.Add(order);
await dbContext.SaveChangesAsync();
}
//Act
var orderDto = new OrderDto
{
Description = "Test Order 2",
OrderLines = new List<OrderLineDto>
{
new OrderLineDto {OrderLineId = order.OrderLines[0].OrderLineId, ProductId = 2, Quantity = 2}
},
OrderId = order.OrderId
};
await _orderRepository.UpdateAsync(Mapper.Map<Order>(orderDto));
//Assert
using (var dbContext = new OrdersDbContext())
{
var updatedOrder = await dbContext.Orders.Include(c => c.OrderLines)
.Where(c => c.OrderId == order.OrderId).SingleAsync();
//updatedOrder.ShouldNotBeNull();
//customerFetch.Id.ShouldNotBeNull();
//customerFetch.Id.ShouldBe(customerDto.Id);
}
}
}
}
和我的订单存储库更新方法
public async Task<Order> UpdateAsync(Order order)
{
var dbOrder = await GetOrderAsync(order.OrderId);
if (dbOrder == null)
throw new Exception($"Invalid Or Missing Order with Id {order.OrderId}");
_dbContext.Update(order);
await _dbContext.SaveChangesAsync();
return order;
}
注意:您可以在此github存储库上获取代码 code repository
答案 0 :(得分:1)
在不使用AsNoTracking
的情况下查询数据库某些记录时,EF Core将开始在当前上下文中对其进行跟踪。因此,当您在代码中更新实体时,EF Core会找到具有相同ID的多个实体,因此会出现错误。 AsNoTracking
是一种解决方案,因为您不希望EF Core跟踪对此的任何修改。在许多情况下,只要您不在上下文中添加/附加/更新具有相同ID的实体,则不使用AsNoTracking
就可以了。但最好在不需要跟踪时明确显示它。
答案 1 :(得分:0)
您的代码几乎没有问题。首先,您无法在需要时随时更新OrdersDbContext。如果这样做,则无法按照说明的异常消息来跟踪实体的实例。
对于单元测试,您需要使用内存数据库或带有模拟库(例如Moq)的模拟OrdersDbContext。
如果调用异步扩展方法,则需要实现async query provider。