【发布时间】:2020-07-23 13:07:55
【问题描述】:
我有一个单元测试来测试在数据库中插入相同的对象两次将给出ArgumentException。我有这门课:
public class Foo
{
public Guid Id { get; set; }
public List<Bar> Bars { get; set; }
}
还有这个单元测试:
[Fact]
public async Task AddFooAsync_ContainsExistingFoo_TrowsArgumentException()
{
// arrange
using var context = new MyDbContext(MockDbContext.CreateInMemoryContext());
var fooRepository = new FooRepository(context, cacheService, myMapper); // cacheService and myMapper are succesfully instantiated elsewhere.
// Add a Foo to the database.
var myFoo = new Foo
{
Id = Guid.Parse("abc-123"),
Bars = new List<Bar> { new Bar { Id = Guid.Parse("def-456") } }
};
_context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
_context.Foo.Add(myFoo);
_context.SaveChanges();
_context.Entry(myFoo).State = EntityState.Detached;
_context.SaveChanges();
// This is a DTO object that is almost the same as the Foo entity above. Same for the Bar List
var fooDTO = new FooDTO
{
Id = Guid.Parse("abc-123"),
Bars = new List<BarDTO> { new BarDTO { Id = Guid.Parse("def-456") } }
}
// act + assert
await Assert.ThrowsAsync<ArgumentException>(() => fooRepository.AddFooAsync(fooDTO));
}
AddFooAsync 方法如下所示:
public async Task<FooDTO> AddFooAsync(FooDTO foo)
{
// use AutoMapper to turn the Foo DTO into a Foo entity.
var dbFoo = _mapper.Map<Foo>(foo);
_dbContext.Foos.Add(dbFoo);
await _dbContext.SaveChangesAsync();
return _mapper.Map<UserDTO>(dbUser);
}
此方法在_dbContext.Foos.Add(dbFoo); 行上崩溃,并抛出InvalidOperationException 而不是我预期的ArgumentException。我收到以下文字:
无法跟踪实体类型“Bar”的实例,因为另一个 键值为“{Id: def-456 }”的实例已经存在 跟踪。附加现有实体时,确保只有一个实体 附加了具有给定键值的实例
我最好的猜测是 EF 也在跟踪 Bar 对象,这在执行双插入时给我带来了问题。解决此问题的最佳方法是什么?
【问题讨论】: