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

EF Core插入JackPot时触发AspNetUsers主键重复异常求助

解决EF Core插入JackPot时重复插入AspNetUsers的问题

问题根源

EF Core尝试插入重复用户记录的核心原因有两点:

  1. JackPot与ApplicationUser的关联关系未明确配置,EF无法识别Owner属性是关联现有用户,而非新建用户;
  2. 从_userManager获取的用户实体未被当前操作的DbContext追踪,EF将其判定为新实体并触发插入操作。

具体修复步骤

1. 完善DbContext的关系映射配置

在OnModelCreating方法中补充JackPot与ApplicationUser的关联规则,明确外键和导航关系:

protected override void OnModelCreating(ModelBuilder builder)
{
    builder.Entity<JackPot>().HasKey(x => x.Id);
    builder.Entity<BetEntity>().HasKey(x => x.Id);
    builder.Entity<ApplicationUserCode>().HasKey(x => x.Id);
    
    // 新增JackPot与ApplicationUser的关联配置
    builder.Entity<JackPot>()
        .HasOne(j => j.Owner)
        .WithMany(u => u.JackPots)
        .HasForeignKey(j => j.UserId)
        .OnDelete(DeleteBehavior.ClientSetNull);
        
    builder.Entity<ApplicationUser>()
        .HasMany(c => c.Beets)
        .WithOne(c => c.Participant)
        .HasForeignKey(c => c.UserId)
        .OnDelete(DeleteBehavior.ClientSetNull);
        
    builder.Entity<JackPot>().Property(x => x.Price).HasColumnType("smallmoney");       
    base.OnModelCreating(builder);
}

2. 确保用户实体被DbContext追踪

在插入JackPot前,将从_userManager获取的用户附加到当前DbContext,告知EF该实体为已存在记录:

var aplicationUser = HttpContext.User.Claims.GetFromClaims();
var user = await _userManager.FindByEmailAsync(aplicationUser.Email ?? string.Empty);
if (user is null)
{
    return NotFound("Lamentablemente, no se ha encontrado ningún usuario con esa información. Por favor, verifica los datos ingresados o regístrate para crear una nueva cuenta.");
}

// 附加用户实体到当前DbContext,标记为已存在状态
_context.Attach(user);

var jackPot = new JackPot(newJackPotViewModel.Name, newJackPotViewModel.Instructions, newJackPotViewModel.Price, newJackPotViewModel.Description, user);
await _jackpotRepository.Add(jackPot);

注:_context为当前操作JackPot的DbContext实例,需确保已正确注入。

3. 移除实体中不必要的默认初始化

BetEntity中默认初始化Participant和JackPot为新实例,会导致EF误判为新实体,需修改:

public class BetEntity : Entity
{
    public BetEntity(ApplicationUser participant, int beetPrice, string imageUrl) : base()
    {
        Participant = participant;
        BeetPrice = beetPrice;
        ImageUrl = imageUrl;
    }
    internal BetEntity()
    {
        
    }
    // 移除默认new ApplicationUser()
    public ApplicationUser Participant { get;private set; }
    public string UserId { get; set; }
    public int BeetPrice { get;private set; }
    public string ImageUrl { get; private set; }
    // 移除默认new JackPot()
    public JackPot JackPot { get; set; }
    public Guid JackPotId { get; set; }
}

原理说明

通过明确关系映射,EF能识别JackPot.Owner是ApplicationUser的导航属性,对应外键UserId;附加用户实体到DbContext后,EF会将其标记为Unchanged状态,不会尝试插入重复记录。

内容的提问来源于stack exchange,提问作者Carlos Henrique Carniatto

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 23:55:23