【问题标题】:EF Core tracking problem when adding Entity to a List将实体添加到列表时出现 EF Core 跟踪问题
【发布时间】:2021-08-13 10:57:22
【问题描述】:

我在开发小型 Blazor WASM 应用程序时遇到了问题。 我的应用程序的一部分是用户可以创建团队并邀请其他用户加入他们的团队的地方。相关的实体类是:

Team.cs

public class Team
    {
        [Key]
        public Guid TeamID { get; set; }        
        public string Name { get; set; }
        public string Abbreviation { get; set; }
        public Guid? BadgeID { get; set; }
        public Guid TownID { get; set; }
        public Guid StatisticsID { get; set; }
        public Guid CaptainID { get; set; }
        public List<AppUserDTO> Players { get; set; } = new();
    }

当用户接受邀请时,他应该被添加到List&lt;AppUserDTO&gt; Players 列表中,我在客户端这样做:

private async Task AcceptInvite()
{
      Team.Players.Add(Player);
      await TeamDataService.UpdateTeam(Team);
}
public async Task UpdateTeam(Team team)
{
    var teamJson =
          new StringContent(JsonSerializer.Serialize(team), Encoding.UTF8, "application/json");

    await _httpClient.PutAsync("api/team", teamJson);
}

但是当我想将更改保存到服务器时,我在服务器端收到以下异常:

System.InvalidOperationException: The instance of entity type 'AppUserDTO' cannot be tracked because another instance with the same key value for {'ID'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.

服务器端代码为:

 public Team UpdateTeam(Team team)
{
       var updatedTeam = _appDbContext.Teams.Include(t => t.Players).FirstOrDefault(t => t.TeamID == team.TeamID);

       if (updatedTeam == null) return null;

       updatedTeam.TeamID = team.TeamID;
       updatedTeam.Name = team.Name;
       updatedTeam.Abbreviation = team.Abbreviation;
       updatedTeam.TownID = team.TownID;
       updatedTeam.StatisticsID = team.StatisticsID;
       updatedTeam.Players = team.Players;
       updatedTeam.CaptainID = team.CaptainID;

       _appDbContext.SaveChanges();
       return updatedTeam;
}

在 _appDbContext.SaveChanges() 方法处弹出异常。

我注意到以下内容:当我将一个实体添加到一个空列表并保存它时,我没有收到任何异常,但如果列表已经有实体,我会收到此错误。

对此有什么解决方案,我相信这是我尝试做的很常见的事情,但我在任何地方都没有找到解决方案。

【问题讨论】:

  • 也许updatedTeam.Players.AddRange(team.Players) ?
  • @SvyatoslavDanyliv 同样的例外。在我看来,您的建议没有意义,因为 updatedTeam 已经有一些球员,而 team 将有相同的球员 + 1,即将加入。
  • 这里很奇怪,为什么TeamAppUserDTO 类。 DTO 不应成为 DB 模型的一部分。

标签: entity-framework entity-framework-core blazor blazor-webassembly


【解决方案1】:

当你执行时:

var updatedTeam = _appDbContext.Teams
   ..Include(t => t.Players).FirstOrDefault(t => t.TeamID == team.TeamID);

...您正在从 Db 中检索现有玩家,而 _appDbContext 正在跟踪它们(通过“ID”)。

现在,当您设置播放器时:

  updatedTeam.Players = team.Players;

...我怀疑 team.Players 包括已经被 _appDbContext 跟踪的玩家。因此你的错误。

你可以试试:

List<Player> playersToAdd = team.Players.Except(updatedTeam.Players);
updatedTeam.AddRange(playersToAdd);

通过这种方式,您不会将重复的玩家添加到已经从初始数据库检索中跟踪的上下文中。

【讨论】:

    猜你喜欢
    • 2013-02-28
    • 1970-01-01
    • 1970-01-01
    • 2018-12-24
    • 1970-01-01
    • 2019-08-09
    • 2018-02-12
    • 1970-01-01
    • 2015-05-08
    相关资源
    最近更新 更多