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

ASP.NET Core Identity中加载并更新继承自ApplicationUser的Employee/Applicant类属性的实现方案

ASP.NET Core Identity中加载并更新继承自ApplicationUser的Employee/Applicant类属性的实现方案

Hey, let's work through why your current code isn't updating the derived class properties and how to fix it. The core issues are twofold:

  1. When you use _userManager.GetUserAsync(User), it only returns an instance of the base ApplicationUser class—even if the user is actually an Employee or Applicant in the database. This means the derived properties are hidden and can't be accessed/updated directly.
  2. Your CreateUser method always spawns an ApplicationUser, so new users never get stored as Employee or Applicant types in the first place.

Let's go through the fixes step by step:


一、先确保EF Core的继承映射配置正确

First, we need to make sure Entity Framework Core properly handles your inheritance hierarchy. By default, EF Core uses Table-Per-Hierarchy (TPH) (all types share one table with a discriminator column), but we can explicitly configure it to avoid surprises:

public partial class AppIdentityDbContext : IdentityDbContext<ApplicationUser>
{
    public AppIdentityDbContext(DbContextOptions<AppIdentityDbContext> options)
        : base(options)
    {
    }

    // Add DbSets for your derived types to make queries easier
    public virtual DbSet<Employee> Employees { get; set; }
    public virtual DbSet<Applicant> Applicants { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        // Explicitly configure TPH inheritance (optional but clear)
        modelBuilder.Entity<ApplicationUser>()
            .HasDiscriminator<string>("UserType")
            .HasValue<ApplicationUser>("StandardUser")
            .HasValue<Employee>("Employee")
            .HasValue<Applicant>("Applicant");

        // Configure the Employee-Department relationship
        modelBuilder.Entity<Employee>()
            .HasOne(e => e.Department)
            .WithMany(d => d.Employees)
            .HasForeignKey(e => e.DepartmentId);
    }
}

二、修改注册逻辑,创建正确的派生类实例

Your CreateUser method was only making ApplicationUser instances. We need to adjust it to create the right type based on user selection (like a dropdown in your registration page):

// Update your CreateUser method to accept a user type parameter
private ApplicationUser CreateUser(string userType)
{
    try
    {
        return userType switch
        {
            "Employee" => Activator.CreateInstance<Employee>(),
            "Applicant" => Activator.CreateInstance<Applicant>(),
            _ => Activator.CreateInstance<ApplicationUser>()
        };
    }
    catch
    {
        throw new InvalidOperationException($"Can't create an instance of the selected user type. Make sure the type has a parameterless constructor.");
    }
}

Then in your registration page's OnPostAsync, call it with the user-selected type:

// Assume your InputModel has a UserType field (from a dropdown)
var user = CreateUser(Input.UserType);
// Continue with your existing registration logic...

三、修改LoadAsync方法,加载派生类属性

Instead of relying on UserManager to get the user, query the DbContext directly to fetch the actual derived type:

First, update your InputModel to include derived properties:

public class InputModel
{
    public string? PhoneNumber { get; set; }
    public string? Address { get; set; }
    // Applicant properties
    public DateOnly? Birthday { get; set; }
    public int? ExperienceYears { get; set; }
    // Employee properties
    public string? DepartmentId { get; set; }
}

Then rewrite the LoadAsync method:

private async Task LoadAsync()
{
    var userId = _userManager.GetUserId(User);
    
    // Query the DbContext to get the actual user type (Employee/Applicant)
    var user = await _context.Users
        .Include(e => (e as Employee)?.Department) // Load Department if it's an Employee
        .FirstOrDefaultAsync(u => u.Id == userId);
    
    if (user == null) return;

    Username = await _userManager.GetUserNameAsync(user);
    Input = new InputModel
    {
        PhoneNumber = await _userManager.GetPhoneNumberAsync(user),
        Address = user.Address,
        // Map derived properties based on user type
        Birthday = (user as Applicant)?.Birthday,
        ExperienceYears = (user as Applicant)?.ExperienceYears,
        DepartmentId = (user as Employee)?.DepartmentId
    };
}

四、修改OnPostAsync方法,更新派生类属性

Again, fetch the actual user type from the DbContext, update the properties, and save via DbContext (since UserManager.UpdateAsync only handles base class properties):

public async Task<IActionResult> OnPostAsync()
{
    var userId = _userManager.GetUserId(User);
    var user = await _context.Users
        .FirstOrDefaultAsync(u => u.Id == userId);
    
    if (user == null)
    {
        return NotFound($"Unable to load user with ID '{userId}'.");
    }

    if (!ModelState.IsValid)
    {
        await LoadAsync();
        return Page();
    }

    // Update base class properties
    user.Address = Input.Address;
    var currentPhone = await _userManager.GetPhoneNumberAsync(user);
    if (Input.PhoneNumber != currentPhone)
    {
        var setPhoneResult = await _userManager.SetPhoneNumberAsync(user, Input.PhoneNumber);
        if (!setPhoneResult.Succeeded)
        {
            StatusMessage = "Unexpected error when updating phone number.";
            return RedirectToPage();
        }
    }

    // Update derived class properties
    if (user is Applicant applicant)
    {
        applicant.Birthday = Input.Birthday;
        applicant.ExperienceYears = Input.ExperienceYears;
    }
    else if (user is Employee employee)
    {
        employee.DepartmentId = Input.DepartmentId;
    }

    // Save all changes via DbContext (includes derived properties)
    await _context.SaveChangesAsync();
    await _signInManager.RefreshSignInAsync(user);

    StatusMessage = "Your profile has been updated successfully!";
    return RedirectToPage();
}

关键注意事项

  • Avoid using UserManager for derived types: UserManager is designed for the base ApplicationUser class, so it can't return or update derived properties directly. Always use the DbContext to fetch the actual user type.
  • Ensure correct user type on registration: If you don't create the right derived type during registration, the user will be stored as ApplicationUser forever, and their derived properties will never exist in the database.
  • Inheritance strategy: We used TPH here (single table with discriminator) because it's the most common and efficient approach. If you need separate tables for each type (TPT), you can adjust the EF Core configuration, but TPH is usually sufficient.

备注:内容来源于stack exchange,提问作者trongtoannguyen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.20 11:18:08