首页 > 解决方案 > 更新语句删除导航属性记录

问题描述

我正在使用 EF Core 向我正在构建的数独 API 添加新游戏。每个游戏都有一个用户,该用户可以担任多个角色。每当我添加新游戏时,我必须手动拉取用户角色并将它们添加回上下文,否则它们会丢失。同样,当我添加新游戏时,会出现用户之前所有其他游戏丢失的情况。我究竟做错了什么?

我试过了

_context.Games.Add(game);

这导致了它自己的一系列问题,然后我尝试了

_context.Games.Update(game);

但我得到了当前的问题:

        public async Task<Game> CreateGame(CreateGameRO createGameRO) {

            var userActionResult = 
                await _userService.GetUser(createGameRO.UserId);
            var difficultyActionResult = 
                await _difficultiesService.GetDifficulty(createGameRO.DifficultyId);

            SudokuMatrix matrix = new SudokuMatrix();
            matrix.GenerateSolution();

            Game game = new Game(
                userActionResult.Value, 
                matrix, 
                difficultyActionResult.Value);

            // EF Core loses reference to the users roles when creating new games.
            // Before we save the new game we pull a reference to the users roles...
            var user = game.User;
            var userRoles = _context.UsersRoles.Where(u => u.UserId == user.Id).ToList();
            //var userGames = _context.Games.Where(g => g.UserId == user.Id).ToList();

            _context.Games.Update(game);
            await _context.SaveChangesAsync();

            // ...then we reattach the users roles to the data context.
            _context.UsersRoles.AddRange(userRoles);
            //_context.Games.AddRange(userGames);
            await _context.SaveChangesAsync();

            return game;
        }

我在我的应用程序中添加了日志记录,并注意到以下生成的 SQL 命令:

      DELETE FROM "Games"
      WHERE "Id" = @p0;
      DELETE FROM "Games"
      WHERE "Id" = @p1;
      DELETE FROM "SudokuCells"
      WHERE "Id" = @p2;
      DELETE FROM "SudokuCells"
      WHERE "Id" = @p3;
      DELETE FROM "SudokuCells"
      WHERE "Id" = @p4;

发生这种情况的情况如下......假设我创建了一个用户 Dean Winchester,然后添加了第二个用户 Sam Winchester。然后我为 Dean 创建了两个新游戏,一切都很好,我为 Sam 创建了两个新游戏,一切都很好……然后我为 Dean 创建了另一个游戏,上面的 SQL 被创建,前两个游戏被删除。

标签: postgresqlentity-framework-core

解决方案


由于没有其他人可以回答这个问题,我将继续这样做。

假设我正在使用 WebAPI 在断开连接的环境中工作,除非我专门跟踪它们,否则上下文不知道我的用户拥有的其他游戏和角色。但是,我在日志中记录了证据,证明 EF 核心正在竭尽全力追踪用户的游戏和角色……并删除它们!

这种行为对我来说毫无意义,如果有人能解释以这种方式处理它的基本逻辑,我将不胜感激。对我来说,更新语句封装删除是反直觉的。

我的解决方案现在看起来像这样:

            Game game = new Game(
                userActionResult.Value, 
                matrix, 
                difficultyActionResult.Value);

            var user = await _context.Users
                .FirstOrDefaultAsync(u => u.Id == userActionResult.Value.Id);

            var userRoles = await _context.UsersRoles
                .Where(ur => ur.UserId == user.Id)
                .ToListAsync();

            var userGames = await _context.Games
                .Where(g => g.UserId == user.Id)
                .ToListAsync();

            _context.Games.Update(game);
            await _context.SaveChangesAsync();

            _context.UsersRoles.AddRange(userRoles);
            await _context.SaveChangesAsync();

            _context.Games.UpdateRange(userGames);
            await _context.SaveChangesAsync();

我必须对数据库进行三次访问以保护我一开始不想接触的数据……这很愚蠢,但它确实有效。

我对这个解决方案不满意。假设一个用户有 1000 个游戏?我必须将所有 1000 个游戏拉入内存...添加我的新游戏...EF 核心然后删除所有以前的 1000 个游戏...然后我必须重新添加 1000 个游戏?


推荐阅读