Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# EF Core 5-更新多对多关系中的实体;违反主键“;错误_C#_Sql Server_Asp.net Core_Entity Framework Core_Many To Many - Fatal编程技术网

C# EF Core 5-更新多对多关系中的实体;违反主键“;错误

C# EF Core 5-更新多对多关系中的实体;违反主键“;错误,c#,sql-server,asp.net-core,entity-framework-core,many-to-many,C#,Sql Server,Asp.net Core,Entity Framework Core,Many To Many,我正在为数据库使用和MSSQL 我有两个类,它们之间有多对多的关系。这些已从模型迁移到数据库。 迁移: migrationBuilder.CreateTable( name: "TournamentUser", columns: table => new { TournamentsId = table.Column<int>(type: "in

我正在为数据库使用和
MSSQL

我有两个类,它们之间有多对多的关系。这些已从模型迁移到数据库。

迁移:

migrationBuilder.CreateTable(
            name: "TournamentUser",
            columns: table => new
            {
                TournamentsId = table.Column<int>(type: "int", nullable: false),
                UsersId = table.Column<int>(type: "int", nullable: false)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_TournamentUser", x => new { x.TournamentsId, x.UsersId });
                table.ForeignKey(
                    name: "FK_TournamentUser_Tournaments_TournamentsId",
                    column: x => x.TournamentsId,
                    principalTable: "Tournaments",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.Cascade);
                table.ForeignKey(
                    name: "FK_TournamentUser_Users_UsersId",
                    column: x => x.UsersId,
                    principalTable: "Users",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.Cascade);
            });
migrationBuilder.CreateTable(
名称:“TournamentUser”,
列:表=>new
{
TournamentsId=table.Column(类型:“int”,可为空:false),
UsersId=table.Column(类型:“int”,可空:false)
},
约束:表=>
{
表.PrimaryKey(“PK_TournamentUser”,x=>new{x.TournamentsId,x.UsersId});
表1.外键(
名称:“FK_TournamentUser_Tournaments_TournamentsId”,
列:x=>x.TournamentsId,
原则:“锦标赛”,
主栏:“Id”,
onDelete:引用。级联);
表1.外键(
名称:“FK_TournamentUser_Users_UsersId”,
列:x=>x.UsersId,
原则性:“用户”,
主栏:“Id”,
onDelete:引用。级联);
});
型号:

public class Tournament
{
    [Key]
    public int Id { get; set; }
    [Required, MaxLength(20)]
    public string Name { get; set; }
    [Required]
    public int MaxPlayers { get; set; }
    public int PlayersCount { get; set; }
    [Required]
    public DateTime Start { get; set; }
    public bool IsStarted { get; set; }
    public bool IsEnded { get; set; }
    public List<User> Users { get; set; }
}

public class User
{
    [Key]
    public int Id { get; set; }
    [Required, MaxLength(15)]
    public string Username { get; set; }
    [Required]
    public string Password { get; set; }
    [Required, MaxLength(20)]
    public string Name { get; set; }
    [Required, MaxLength(20)]
    public string Surname { get; set; }
    [JsonIgnore]
    public List<Tournament> Tournaments { get; set; }
}
公开课比赛
{
[关键]
公共int Id{get;set;}
[必需,最大长度(20)]
公共字符串名称{get;set;}
[必需]
公共整数MaxPlayers{get;set;}
public int PlayersCount{get;set;}
[必需]
公共日期时间开始{get;set;}
公共布尔值已开始{get;set;}
公共布尔值为{get;set;}
公共列表用户{get;set;}
}
公共类用户
{
[关键]
公共int Id{get;set;}
[必需,最大长度(15)]
公共字符串用户名{get;set;}
[必需]
公共字符串密码{get;set;}
[必需,最大长度(20)]
公共字符串名称{get;set;}
[必需,最大长度(20)]
公共字符串姓氏{get;set;}
[JsonIgnore]
公开列表锦标赛{get;set;}
}
所以当我尝试更新锦标赛模型时

[HttpPut]
公共异步任务放置([FromBody]锦标赛)
{
_上下文。锦标赛。更新(锦标赛);
wait_context.SaveChangesAsync();
返回CreateDataAction(nameof(GetTournament),新的{id=tournament.id},tournament);
}
我得到这个错误

Microsoft.Data.SqlClient.SqlException(0x80131904):违反 主键约束“PK_TournamentUser”。无法插入重复项 输入对象“dbo.TournamentUser”。重复的键值为(1,1)

有什么可能的解决方案?我想保留我的多对多表,因为每次我更新
锦标赛
时,都可以删除或添加
锦标赛的用户

编辑:
下面显示了锦标赛对象数据-


如果要更新Tourment,请尝试从torment对象中删除用户

 public async Task<ActionResult<Tournament>> Put([FromBody] Tournament tournament)
    {
         tournament.Users=null;
        _context.Tournaments.Update(tournament);
        await _context.SaveChangesAsync();
.....
   
    }

解决方案:

要更新
锦标赛
实体,请仅使用以下方法-

\u context.Entry(锦标赛).State=EntityState.Modified;
wait_context.SaveChangesAsync();
解释:

  • 如果实体具有
    Id
    (自动生成的主键)值,则
    Update()
    方法将实体标记为
    Modified
    ,如果实体没有
    Id
    值,则标记为
    Added
    。如果使用实体图(具有相关实体的实体)调用该方法,则任何相关实体也是如此。然后,在下一次
    SaveChanges()
    调用中,EF根据实体是否标记为
    Modified
    Added
    ,为实体生成更新和/或插入命令。关键是,
    Update()
    方法不仅更新实体,还可以插入新实体

  • 在您的案例中,通过查看模型,EF可以判断
    锦标赛
    用户
    处于多对多关系中,并且在数据库级别存在一个加入实体
    锦标赛用户
    。但由于您从外部接收实体图,EF不会跟踪它们,并且它无法判断此锦标赛的
    TournamentUser
    实体以及相关用户是否已存在于数据库中

  • 使用实体图调用
    Update()
    方法时,锦标赛、相关用户以及与其相关的加入实体(
    TournamentUser
    )都将成为更新操作的主题。EF尝试创建连接实体,就像创建/插入没有
    Id
    值的新实体一样

  • EF为
    锦标赛用户
    实体生成插入命令,并为
    锦标赛
    用户
    实体生成更新命令。但是在数据库级别,由于
    TournamentUser
    链接已经存在,您会得到
    违反主键的错误

  • -

    \u context.Entry(锦标赛).State=EntityState.Modified;
    

    上述建议仅将锦标赛明确标记为
    已修改
    。因此,EF不必查看任何相关实体,也不必推断任何关系,只为锦标赛生成更新命令。

    我从中找到了解决方案

    我对代码做了一些修改,因为最初它是从表中删除用户,我得到了我想要的结果

    public async Task<ActionResult<Tournament>> Put([FromBody] Tournament tournament)
        {
            var _tournament = _context.Tournaments.Include(t => t.Users).FirstOrDefault(t => t.Id == tournament.Id);
            _context.Entry(_tournament).CurrentValues.SetValues(tournament);
            var _users = _tournament.Users.ToList();
            // Adds new Users
            foreach (var tournamentUser in tournament.Users)
            {
                if (_users.All(i => i.Id != tournamentUser.Id))
                {
                    _tournament.Users.Add(tournamentUser);
                }
            }
            // Removes old Users
            foreach (var tournamentUser in _users)
            {
                if (tournament.Users.FirstOrDefault(tu => tu.Id == tournamentUser.Id) == null)
                {
                    _tournament.Users.Remove(tournamentUser);
                }
            }
            await _context.SaveChangesAsync();
    
            return CreatedAtAction(nameof(GetTournament), new { id = tournament.Id }, tournament);
        }
    
    public异步任务Put([FromBody]锦标赛)
    {
    var\u tournament=\u context.Tournaments.Include(t=>t.Users).FirstOrDefault(t=>t.Id==tournament.Id);
    _context.Entry(_锦标赛).CurrentValues.SetValues(锦标赛);
    var_users=_tournament.users.ToList();
    //添加新用户
    foreach(锦标赛中的var tournamentUser.Users)
    
    var existing = _context
                  .Tournaments
                  .Include(u=>u.Users)
                  .FirstOrDefault(t=> t.Id== tournament.Id);
    
    if(existing==null) return ...error
    
    _context.Entry(existing).CurrentValues.SetValues(tournment);
    
    _context.SaveChanges();
    
    public async Task<ActionResult<Tournament>> Put([FromBody] Tournament tournament)
        {
            var _tournament = _context.Tournaments.Include(t => t.Users).FirstOrDefault(t => t.Id == tournament.Id);
            _context.Entry(_tournament).CurrentValues.SetValues(tournament);
            var _users = _tournament.Users.ToList();
            // Adds new Users
            foreach (var tournamentUser in tournament.Users)
            {
                if (_users.All(i => i.Id != tournamentUser.Id))
                {
                    _tournament.Users.Add(tournamentUser);
                }
            }
            // Removes old Users
            foreach (var tournamentUser in _users)
            {
                if (tournament.Users.FirstOrDefault(tu => tu.Id == tournamentUser.Id) == null)
                {
                    _tournament.Users.Remove(tournamentUser);
                }
            }
            await _context.SaveChangesAsync();
    
            return CreatedAtAction(nameof(GetTournament), new { id = tournament.Id }, tournament);
        }