You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 7.0多对多关联时AspNetUsers主键重复插入错误排查

问题:多对多关联时AspNetUsers主键重复插入错误

环境:.NET 7.0、Code First、仓储模式、规范模式

建立Report与ApplicationUser多对多关联时,触发AspNetUsers表主键重复插入错误,相关代码如下:

ApplicationUser类

public class ApplicationUser : IdentityUser, IAuditable
{
    // ...
    public virtual IList<Report> Reports { get; set; }
}

Report类

public class Report : EntityBase, IAuditable
{
    // ...
    public virtual IList<ApplicationUser> Users { get; set; }
}

DbContext

public class ConstructionReportContext : IdentityDbContext<ApplicationUser>
{
    // ...
    public DbSet<ApplicationUser>? ApplicationUsers { get; set; }
    public DbSet<Report>? ConstructionReports { get; set; }
}

数据库迁移已生成关联表ApplicationUserReport,包含指向User和Report的外键。

业务逻辑AddUserToReport流程:获取关联用户的Report实体 → 通过UserManager查找用户 → 检查用户未关联后添加到Report的Users集合 → 调用仓储EditAsync保存,报错信息:

2023-11-07 15:34:58.480 -03:00 [ERR] InnerException: | Trace-id: '95237348-5f39-4ed8-9b86-5fb5731b880b'
Microsoft.Data.SqlClient.SqlException (0x80131904): Violation of PRIMARY KEY constraint 'PK_AspNetUsers'. Cannot insert duplicate key in object 'dbo.AspNetUsers'. The duplicate key value is (ddc9205d-aa3c-479d-9217-01c3404a4c61).
The statement has been terminated.

尝试附加用户对象后问题仍存在,疑问:UserManager的FindByIdAsync是否会返回分离状态的对象?


解决方案

核心原因

UserManager默认使用的DbContext和仓储层的DbContext可能不是同一个实例,或者FindByIdAsync返回的用户实体处于分离状态。当将这个分离的用户实体添加到Report的Users集合并保存时,EF Core会将该用户视为新实体,尝试插入到AspNetUsers表,导致主键冲突。

解决步骤

  1. 统一DbContext实例
    检查依赖注入配置,确保仓储层和UserManager共享同一个Scoped生命周期的DbContext实例(避免注册为Transient,防止每次请求创建新实例)。

  2. 正确附加用户实体并标记状态
    即使尝试过附加,需明确将用户实体标记为已存在状态:

    var user = await _userManager.FindByIdAsync(userId);
    var dbContext = _constructionReportContext;
    // 附加用户,若已被跟踪则忽略
    var entry = dbContext.Attach(user);
    // 标记为已存在,避免EF尝试插入
    entry.State = EntityState.Unchanged;
    
    report.Users.Add(user);
    await _reportRepository.EditAsync(report);
    
  3. 用ID直接关联,避免加载完整实体
    无需加载完整用户实体,直接通过ID操作关联关系:

    var report = await _reportRepository.GetByIdAsync(reportId);
    // 创建仅含ID的用户对象并附加
    var user = new ApplicationUser { Id = userId };
    _constructionReportContext.Attach(user).State = EntityState.Unchanged;
    report.Users.Add(user);
    await _constructionReportContext.SaveChangesAsync();
    
  4. 移除多余的ApplicationUsers DbSet
    IdentityDbContext<ApplicationUser>已默认包含用户的DbSet,手动添加public DbSet<ApplicationUser>? ApplicationUsers { get; set; }可能导致实体跟踪冲突,建议删除该行。

内容的提问来源于stack exchange,提问作者pata

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 14:02:53