EF Core插入JackPot时触发AspNetUsers主键重复异常求助
解决EF Core插入JackPot时重复插入AspNetUsers的问题
问题根源
EF Core尝试插入重复用户记录的核心原因有两点:
- JackPot与ApplicationUser的关联关系未明确配置,EF无法识别
Owner属性是关联现有用户,而非新建用户; - 从
_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
相关产品推荐
相关产品推荐

