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

问题描述 投票:0回答:1

我正在使用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);
        }

[运行测试时,我遇到错误:“无法跟踪实体类型'Game'的实例,因为已经跟踪了另一个键值为'{Id:2}'的实例。在附加现有实体时,请确保只能附加一个具有给定键值的实体实例。“

出于比较目的,这是确实起作用的添加功能:

[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);
        }

我已经尝试了几种方法来回答所提出的类似问题,但是它们都不适合我。我的存储库en服务的范围仅限于Startup.cs,并且在createdb()函数als中分离实体似乎不起作用。还有其他想法吗?

c# visual-studio unit-testing entity-framework-core in-memory-database
1个回答
0
投票

我认为它来自您的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进行数据初始化和读取数据,我建议您使用另一个上下文,以确保您可以正常使用。

© www.soinside.com 2019 - 2024. All rights reserved.