无法跟踪实体类型 'Game' 的实例,因为已跟踪具有键值的另一个实例

The instance of entity type 'Game' cannot be tracked because another instance with the key value is already being tracked

我正在对使用 Entity Framework Core 使用内存数据库创建的应用程序进行单元测试,但我 运行 遇到了我的一个函数的问题。到目前为止,我已经测试过通过 Id 获取游戏(有效)、将游戏添加到集合中(也有效)和更新集合中的游戏(无效)。

功能码:

 [TestMethod()]
        public async Task UpdateGameAsyncTest()
        {
            //Arrange
            await CreateDb();

            GameDto gameDto = new GameDto()
            {
                Id = 2,
                Team1 = "PSG",
                Team2 = "AZ",
                Date = DateTime.UtcNow
            };

            //Act
            var id = await _gameService2.UpdateGameAsync(gameDto);
            var game = await _gameService2.GetGameAsync(id);

            //Assert
            Assert.AreEqual("AZ", game.Team1);
        }

我的服务层中的 UpdateGameAsync():

public async Task<int> UpdateGameAsync(GameDto game)
        {
            var gameEntity = game.ToEntity();

            return await _gameRepository.UpdateGameAsync(gameEntity);
        }

我的存储库层中的 UpdateGameAsync():

public async Task<int> UpdateGameAsync(Game game)
        {
            if (game.Result != null)
            {
                if (game.Result.Length == 3 && game.Result.Substring(1, 1) == "-")
                {
                    game.typeResult = await CheckTypeResult(game.Result);
                }
            }
            _dbContext.Games.Update(game);

            return await AutoSaveChangesAsync();
        }

CreateDb():

public async Task CreateDb()
        {
            var options = new DbContextOptionsBuilder<StrikeNetDbContext>()
                .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
                .EnableSensitiveDataLogging()
                .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
                .Options;

            var dbContext = new StrikeNetDbContext(options);

            if (await dbContext.Games.CountAsync() <= 0)
            {
                Game g1 = new Game()
                {
                    Id = 1,
                    Team1 = "FCB",
                    Team2 = "BVB",
                    Date = DateTime.UtcNow
                };
                Game g2 = new Game()
                {
                    Id = 2,
                    Team1 = "PSG",
                    Team2 = "PSV",
                    Date = DateTime.UtcNow
                };
                Game g3 = new Game()
                {
                    Id = 3,
                    Team1 = "Ajax",
                    Team2 = "Feyenoord",
                    Date = DateTime.UtcNow
                };
                dbContext.Games.Add(g1);
                dbContext.Games.Add(g2);
                dbContext.Games.Add(g3);
                await dbContext.SaveChangesAsync();
            }

            var gameRepository = new GameRepository(dbContext);
            _gameService2 = new GameService(gameRepository);
        }

当运行测试我运行进入错误:"The instance of entity type 'Game' cannot be tracked because another instance with the key value '{Id: 2}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached."

为了进行比较,这里是添加函数,它确实有效:

[TestMethod()]
        public async Task AddGameAsyncTest()
        {
            //Arrange
            await CreateDb();

            GameDto game = new GameDto()
            {
                Team1 = "Juve",
                Team2 = "Real",
                Date = DateTime.UtcNow
            };

            //Act
            var id = await _gameService2.AddGameAsync(game);
            var expected = await _gameService2.GetGameAsync(id);

            //Assert
            Assert.AreEqual("Juve", expected.Team1);
        }

我尝试了几种方法来回答类似的问题,但 none 对我有用。我确实将我的存储库 en 服务限定在 Startup.cs 范围内,并且分离 createdb() 函数中的实体似乎也不起作用。还有人有其他想法吗?

我认为它来自您的 UpdateGameAsync 方法。如果您在内部调用 EF Update,如文档所述,您尝试跟踪实体

Begins tracking the given entity in the Microsoft.EntityFrameworkCore.EntityState.Modified

但是,我认为您的实体已经被跟踪,因为我觉得您在 CreateDb 中使用了相同的 dbContext,并且这一行开始跟踪您的实体:

dbContext.Games.Add(g2);

您可以检查您的实体是否在您的存储库中被跟踪:

_context.Games.Local.Any(g => g.Id == entity.Id)

如果已经被追踪,则不需要调用EF Update()

顺便说一句,如果您的实际情况不使用相同的 DbContext 进行数据初始化和数据读取,我建议使用另一个上下文以确保它能按您的要求工作。