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

Blazor Server异步Task<string>无法显示字符串及用户表关联问题

解决Blazor排班表异步获取用户名及数据库关联问题

一、异步方法显示异常的解决办法

你直接在组件渲染代码里调用@GetNameFromIdAsync(day.Manager1)会输出Task对象的字符串结果,而非实际用户名——因为异步方法返回的是Task<string>,必须通过@await获取结果。但更高效的做法是提前预加载所有需要的用户名,避免循环中多次调用异步方法(频繁访问数据库/Identity服务会导致性能问题)。

1. 预加载用户名映射字典

在组件代码部分添加字典存储用户ID与用户名的映射,在初始化时批量查询:

private Dictionary<string, string> _userIdToNameMap = new Dictionary<string, string>();
private List<DayOfWeek> _rosterDays = new List<DayOfWeek>(); // 建议改名避免和系统类型冲突

protected override async Task OnInitializedAsync()
{
    // 先获取所有排班数据
    _rosterDays = await context.DayOfWeek.ToListAsync();
    
    // 收集所有需要查询的用户ID,去重
    var allUserIds = _rosterDays.SelectMany(day => new[] 
    {
        day.Manager1, day.Manager2, day.Kitchen1, day.Kitchen2, day.Kitchen3,
        day.Driver1, day.Driver2, day.Driver3
    })
    .Where(id => !string.IsNullOrEmpty(id))
    .Distinct()
    .ToList();
    
    // 批量查询用户名并填充字典
    foreach (var id in allUserIds)
    {
        var user = await UserManager.FindByIdAsync(id);
        _userIdToNameMap[id] = user?.FirstName ?? "未分配";
    }
}

2. 修改渲染代码

直接从字典中读取用户名,无需重复调用异步方法:

@foreach (var day in _rosterDays)
{
    <tr>
        <td>@day.Day</td>
        <td>@day.OpenTime</td>
        <td>@day.CloseTime</td>
        <td>@(_userIdToNameMap.TryGetValue(day.Manager1, out var name) ? name : "未分配")</td>
        <td>@(_userIdToNameMap.TryGetValue(day.Manager2, out var name2) ? name2 : "未分配")</td>
        <td>@(_userIdToNameMap.TryGetValue(day.Kitchen1, out var name3) ? name3 : "未分配")</td>
        <td>@(_userIdToNameMap.TryGetValue(day.Kitchen2, out var name4) ? name4 : "未分配")</td>
        <td>@(_userIdToNameMap.TryGetValue(day.Kitchen3, out var name5) ? name5 : "未分配")</td>
        <td>@(_userIdToNameMap.TryGetValue(day.Driver1, out var name6) ? name6 : "未分配")</td>
        <td>@(_userIdToNameMap.TryGetValue(day.Driver2, out var name7) ? name7 : "未分配")</td>
        <td>@(_userIdToNameMap.TryGetValue(day.Driver3, out var name8) ? name8 : "未分配")</td>
        <AuthorizeView Roles="Administrator">
            <td><a href="@($"rosterdays/edit?id={day.Id}")"><button class="btn-warning">Edit</button></a></td>
            <td><a href="@($"rosterdays/delete?id={day.Id}")"><button class="btn-danger">Delete</button></a></td>
        </AuthorizeView>
    </tr>
}

注:如果一定要直接在渲染时调用异步方法,可改用@await GetNameFromIdAsync(day.Manager1),但此方式会在循环中触发多次异步请求,性能较差,不推荐。

二、数据库中关联ApplicationUser与排班表

可以通过外键和EF Core导航属性,将ASP.NET Identity的ApplicationUser表与你的排班表关联,无需每次调用UserManager查询用户信息。

1. 修改排班表实体类

建议将实体类名改为RosterDay(避免和系统System.DayOfWeek冲突),添加外键和导航属性:

public class RosterDay
{
    public int Id { get; set; }
    public string Day { get; set; }
    public TimeSpan OpenTime { get; set; }
    public TimeSpan CloseTime { get; set; }
    
    // 外键属性,指向AspNetUsers表的Id
    public string Manager1Id { get; set; }
    public string Manager2Id { get; set; }
    public string Kitchen1Id { get; set; }
    public string Kitchen2Id { get; set; }
    public string Kitchen3Id { get; set; }
    public string Driver1Id { get; set; }
    public string Driver2Id { get; set; }
    public string Driver3Id { get; set; }
    
    // 导航属性,用于EF Core加载关联用户
    [ForeignKey(nameof(Manager1Id))]
    public ApplicationUser Manager1 { get; set; }
    [ForeignKey(nameof(Manager2Id))]
    public ApplicationUser Manager2 { get; set; }
    // 其余岗位的导航属性同理添加
}

2. 配置DbContext

在你的数据库上下文类中添加DbSet,并配置外键关系:

public class AppDbContext : IdentityDbContext<ApplicationUser>
{
    public DbSet<RosterDay> RosterDays { get; set; }
    
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
    {
    }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        
        // 配置外键关系:删除用户时将排班表中的外键设为null
        modelBuilder.Entity<RosterDay>()
            .HasOne(r => r.Manager1)
            .WithMany()
            .HasForeignKey(r => r.Manager1Id)
            .OnDelete(DeleteBehavior.SetNull);
        
        // 其余岗位的外键关系同理配置
    }
}

3. 查询时直接加载关联用户

查询排班数据时,通过Include直接加载关联的用户信息,无需调用UserManager:

_rosterDays = await context.RosterDays
    .Include(r => r.Manager1)
    .Include(r => r.Manager2)
    .Include(r => r.Kitchen1)
    // 其余岗位的Include
    .ToListAsync();

渲染时直接读取用户的FirstName:

<td>@day.Manager1?.FirstName ?? "未分配"</td>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 03:05:15