【问题标题】:EF core many to many relation violation of primary key constraint entityEF核心多对多关系违反主键约束实体
【发布时间】:2021-02-03 18:43:06
【问题描述】:

我想将项目添加到测试数据库以进行集成测试。 这些表具有多对多关系(我在数据库上下文中配置它们)我想将新记录添加到监视列表但 AddAsync 抛出 DbUpdate 异常

违反主键约束“PK_Movies”。无法在对象“dbo.Movies”中插入重复键。重复键值为 (f48bd131-79ad-47bc-8cf2-1ece8ba648c2)。 声明已终止。

EF 认为我想更新电影实体,但我想将项目添加到监视列表和链接表 (MovieWatchlist)

我的项目基于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();
    }

那我该怎么办?

【问题讨论】:

    标签: entity-framework asp.net-core


    【解决方案1】:

    我相信您的问题是 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);
    

    让我知道它是否有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-17
      • 1970-01-01
      • 2021-06-11
      • 2016-03-16
      • 1970-01-01
      • 1970-01-01
      • 2014-10-16
      • 1970-01-01
      相关资源
      最近更新 更多