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

如何在EF Core IQueryable投影中本地化枚举类型?

问题描述

我有一个ASP.NET Web Api,在获取全部数据的方法中,使用EF Core IQueryable从数据库检索数据,再通过ProjectTo将领域类映射为响应类,随后将该IQueryable传入DevExtreme库的LoadAsync方法中实现搜索、过滤与分页。

业务代码如下:

public override async Task HandleAsync(DataSourceLoadOptions req, CancellationToken ct)
{
    var feature = this.CreateFeature(_mapper, () => new GetReservationsQueryFeature());
    Result<IQueryable<Domain.Reservation>> result = await _mediator.SendRequestAsync(feature, ct);

    if (result.IsSuccess)
    {
        var cultureInfo = new CultureInfo(feature.Language);
        var queryResult = await DataSourceLoader.LoadAsync(result.Payload.ProjectTo<GetReservationResponse>(_mapper.ConfigurationProvider), req, ct);
        // 需要在此实现Status的本地化,且不能遍历queryResult
        await SendOkAsync(queryResult, cancellation: ct);
    }
    else
    {
        await this.SendIssueAsync(result.Issue, ct);
    }
}

对应的AutoMapper映射配置:

public class GetReservationMappingProfile : Profile
{
    public GetReservationMappingProfile()
    {
        CreateMap<Core.ReservationCore.Domain.Reservation, GetReservationResponse>()
            .ForMember(dest => dest.Uid, opt => opt.MapFrom(src => src.Uid))
            .ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.Status))
            .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name))
            // 其他属性映射
    }
}

现在需要基于cultureInfo对Status枚举属性进行本地化,已有对应的.resx本地化资源文件,要求不使用额外的for/foreach循环遍历queryResult,请问如何实现?


解决方案

方案1:通过AutoMapper自定义值解析器实现映射阶段本地化

该方案在AutoMapper的ProjectTo映射过程中完成枚举本地化,直接将领域模型的枚举值转换为对应语言的字符串,后续DevExtreme处理的已是本地化后的数据,无需额外遍历。

步骤1:创建枚举本地化值解析器

public class EnumLocalizationResolver<TEnum> : IValueResolver<object, object, string> where TEnum : Enum
{
    public string Resolve(object source, object destination, string destMember, ResolutionContext context)
    {
        // 从AutoMapper上下文获取请求级别的CultureInfo
        if (!context.Items.TryGetValue("CultureInfo", out var cultureObj) || cultureObj is not CultureInfo cultureInfo)
        {
            cultureInfo = CultureInfo.CurrentUICulture;
        }

        if (source is TEnum enumValue)
        {
            // 替换为你的资源文件名,确保资源文件访问修饰符为public
            return EnumResources.ResourceManager.GetString(enumValue.ToString(), cultureInfo) 
                   ?? enumValue.ToString(); // 本地化失败时返回枚举原始值
        }
        return string.Empty;
    }
}

步骤2:修改AutoMapper映射配置

将Status属性的映射改为使用自定义解析器:

public class GetReservationMappingProfile : Profile
{
    public GetReservationMappingProfile()
    {
        CreateMap<Core.ReservationCore.Domain.Reservation, GetReservationResponse>()
            .ForMember(dest => dest.Uid, opt => opt.MapFrom(src => src.Uid))
            // 指定使用枚举本地化解析器,替换ReservationStatus为你的实际枚举类型
            .ForMember(dest => dest.Status, opt => opt.MapFrom<EnumLocalizationResolver<ReservationStatus>>())
            .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name));
        // 其他属性映射
    }
}

步骤3:在请求处理中传递CultureInfo到AutoMapper上下文

修改ProjectTo的调用,通过Options传递当前请求的CultureInfo:

if (result.IsSuccess)
{
    var cultureInfo = new CultureInfo(feature.Language);
    // 传递CultureInfo到AutoMapper上下文
    var mappedQuery = result.Payload.ProjectTo<GetReservationResponse>(_mapper.ConfigurationProvider, opt =>
        opt.Items["CultureInfo"] = cultureInfo);
    
    var queryResult = await DataSourceLoader.LoadAsync(mappedQuery, req, ct);
    await SendOkAsync(queryResult, cancellation: ct);
}

注意事项

  1. 确保.resx资源文件的访问修饰符设置为public,否则ResourceManager无法读取资源内容。
  2. 资源文件的键名需与枚举值的字符串形式完全一致,例如枚举值ReservationStatus.Confirmed对应资源键Confirmed。
  3. 若需要支持多语言切换,需确保不同语言的.resx文件(如EnumResources.en.resx、EnumResources.zh-CN.resx)已正确配置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 18:24:04