为IdentityUser添加外键,创建用户时提示主表外键冲突?


[NotMapped]
public class AppUser:IdentityUser
{
    [Required]
    public string RealName { get; set; } = default!;

    [Required]
    [ForeignKey("DepartmentId")]
    public Department Department { get; set; } = default!;
}
public class Department
  {
    [Key]
    public int DepartmentId { get; set; }

    [Required]
    public string Name { get; set; } = default!;

    public Department? Parent { get; set; }
}
if (ModelState.IsValid)
{
    var user = new AppUser { UserName = model.UserName, RealName = model.RealName};
    var dep = _departmentRepository.Departments.FirstOrDefault(d => d.DepartmentId == Id);
    user.Department = dep;
    
    if (model.Password != null)
    {
        var result = await userManager.CreateAsync(user, model.Password);
        if (result.Succeeded)
        {
            return RedirectToAction(nameof(Index));
        }
    }
   return View(model);
}

扩展的IdentityUser,增加了Department外键,虽然从主表Departments中找到了实例并赋值给了user的Department属性,但是CreateAsync的时候仍然要在主表Departments中添加此Department实例,怎么解决?急!

引用 皆我百晓生 小程序回复内容作答:
您在扩展的 AppUser 类中添加了 Department 外键属性,并在创建用户时尝试将对应的部门赋值给该属性。然而,即使您已经在主表 Departments 中找到了部门实例并赋值给了 userDepartment 属性,但 CreateAsync 方法仍会尝试在主表 Departments 中添加该部门实例,导致外键冲突。

要解决这个问题,您可以将外键属性 Department 声明为导航属性,在数据库迁移时设置外键关系。这样,EF Core 将会自动处理外键的关联关系,而不会尝试向主表 Departments 中添加已经存在的部门实例。

您可以按照以下步骤进行修改:

  1. 修改 AppUser 类的属性声明,将 Department 改为 DepartmentId 外键属性:

    [Required]
    [ForeignKey("Department")]
    public int DepartmentId { get; set; }
    
    public Department Department { get; set; } = default!;
    
  2. 在数据库上下文中描述 AppUser 类与 Departments 表之间的关系:

    protected override void OnModelCreating(ModelBuilder builder)
    {
        // 其他配置代码...
        
        builder.Entity<AppUser>()
            .HasOne(u => u.Department)
            .WithMany()
            .HasForeignKey(u => u.DepartmentId)
            .OnDelete(DeleteBehavior.Restrict);
        
        // 其他配置代码...
    }
    

通过以上修改,EF Core 将会正确处理 AppUser 类与 Departments 表之间的外键关系,而不会尝试在 CreateAsync 方法中向 Departments 表中添加已经存在的部门实例,从而解决外键冲突的问题。

【以下回答由 GPT 生成】

在给user.Department赋值时,只是将Department实例赋给了user.Department属性,并没有在数据库中将该实例插入到Departments表中。因此,在调用CreateAsync方法时,会提示主表外键冲突。为了解决这个问题,可以采取以下两种方案之一:

方案一:使用导航属性

Department类中添加一个导航属性来关联AppUser类,然后在创建Department实例时,将它关联到AppUser实例上,这样在调用CreateAsync方法时就不会提示主表外键冲突。

修改AppUser类:

[NotMapped]
public class AppUser: IdentityUser
{
    [Required]
    public string RealName { get; set; } = default!;

    [Required]
    public int DepartmentId { get; set; }

    [ForeignKey("DepartmentId")]
    public Department Department { get; set; } = default!;
}

修改Department类:

public class Department
{
    [Key]
    public int DepartmentId { get; set; }

    [Required]
    public string Name { get; set; } = default!;

    public Department? Parent { get; set; }

    public ICollection<AppUser> Users { get; set; } // 添加导航属性
}

修改创建用户的代码:

if (ModelState.IsValid)
{
    var user = new AppUser { UserName = model.UserName, RealName = model.RealName };
    var dep = _departmentRepository.Departments.FirstOrDefault(d => d.DepartmentId == Id);
    user.DepartmentId = dep.DepartmentId; // 使用DepartmentId属性
    user.Department = dep;

    if (model.Password != null)
    {
        var result = await userManager.CreateAsync(user, model.Password);
        if (result.Succeeded)
        {
            return RedirectToAction(nameof(Index));
        }
    }
    return View(model);
}

方案二:手动保存Department实例

在调用CreateAsync方法前,先将Department实例保存到Departments表中。

修改创建用户的代码:

if (ModelState.IsValid)
{
    var user = new AppUser { UserName = model.UserName, RealName = model.RealName };
    var dep = _departmentRepository.Departments.FirstOrDefault(d => d.DepartmentId == Id);
    user.Department = dep;

    // 保存Department实例
    _departmentRepository.Save(dep);

    if (model.Password != null)
    {
        var result = await userManager.CreateAsync(user, model.Password);
        if (result.Succeeded)
        {
            return RedirectToAction(nameof(Index));
        }
    }
    return View(model);
}

这里假设有一个_departmentRepository的仓储类,并且提供了Save方法来保存Department实例到数据库中。具体的保存逻辑需要根据你的数据访问层实现来确定。

以上是两种解决方案,你可以根据实际情况选择其中一种来解决你的问题。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^