我想将项目添加到测试数据库以进行集成测试。 这些表具有多对多关系(我在数据库上下文中配置它们)我想向监视列表表添加新记录但 AddAsync 抛出 DbUpdate 异常
<块引用>违反 PRIMARY KEY 约束“PK_Movies”。无法在对象“dbo.Movies”中插入重复键。重复的键值为 (f48bd131-79ad-47bc-8cf2-1ece8ba648c2)。 声明已终止。
EF 认为我想更新电影实体,但我想将项目添加到监视列表和链接表(电影监视列表)
我的项目基于 CleanArchitecture
public class Movie
{
[Key]
public Guid Id { get; set; } = Guid.NewGuid();
public string PrimaryTitle { get; set; }
public string OriginalTitle { get; set; }
public ICollection<Watchlist> Watchlists { get; set; }
}
public class Watchlist
{
[Key]
public Guid Id { get; set; } = Guid.NewGuid();
public bool IsPrivate { get; set; }
public Guid UserId { get; set; }
public ICollection<Movie> Movies { get; set; }
}
[Test]
public static async Task ShouldRemoveMovieFromWatchlist<TEntity>()
{
var userId = Guid.NewGuid();
var movieList = await GetAsync();
var watchlist = new Watchlist { Id = Guid.NewGuid(), UserId = userId, Movies = moviesList};
await AddAsync(watchlist);
// Act
var command = new RemoveMovieFromWatchlistCommand { MovieId = movieId, WatchlistId = watchlist.Id };
var id = await SendAsync(command);
var result = Include<Watchlist>(id,e => e.Movies);
// Assert
result.Should().NotBeNull();
result.Movies.Should().HaveCount(0);
}
private static IServiceScopeFactory _scopeFactory;
public static async Task AddAsync<TEntity>(TEntity entity)
where TEntity : class
{
using var scope = _scopeFactory.CreateScope();
var context = scope.ServiceProvider.GetService<ApplicationDbContext>();
var dbSet = context.Set<TEntity>();
dbSet.Add(entity);
await context.SaveChangesAsync();
}
public static async Task<List<TEntity>> GetAsync<TEntity>()
where TEntity : class
{
using var scope = _scopeFactory.CreateScope();
var context = scope.ServiceProvider.GetService<ApplicationDbContext>();
return await context.Set<TEntity>().ToListAsync();
}
那我该怎么办?
答案 0 :(得分:0)
我相信您的问题是 EF Core 的更改跟踪器没有跟踪给定的实体,因为当您调用 AddAsync()
时,它会创建一个新的范围和一个新的 DbContext
。
我最近开始使用相同的集成测试方法,它很棒,但是如果不对其进行大量扩展,测试辅助方法将无法让您走得更远。处理 DbContext
的更好方法可能是为每个测试用例实例化一个,而不是每个操作一个。
无论如何,一种简单的解决方案是将给定的实体附加到与插入新 DbContext
相同的范围内的当前 Watchlist
。对执行此更改的附加方法进行粗略修改:
public static async Task AddAsync<TEntity>(TEntity entity, IEnumerable<object> attachThese = null)
where TEntity : class
{
using var scope = _scopeFactory.CreateScope();
var context = scope.ServiceProvider.GetService<ApplicationDbContext>();
if (attachThese != null)
{
context.AttachRange(attachThese);
}
var dbSet = context.Set<TEntity>();
dbSet.Add(entity);
await context.SaveChangesAsync();
}
记得将电影列表添加到观看列表:
var watchlist = new Watchlist { Id = Guid.NewGuid(), UserId = userId, Movies = moviesList};
然后在你的测试中这样调用它:
await AddAsync(watchlist, movieList);
让我知道它是否有效/无效。