如何在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); }
注意事项
- 确保.resx资源文件的访问修饰符设置为public,否则ResourceManager无法读取资源内容。
- 资源文件的键名需与枚举值的字符串形式完全一致,例如枚举值
ReservationStatus.Confirmed对应资源键Confirmed。 - 若需要支持多语言切换,需确保不同语言的.resx文件(如
EnumResources.en.resx、EnumResources.zh-CN.resx)已正确配置。
内容的提问来源于stack exchange,提问作者Rasim Ismatulin
相关产品推荐
相关产品推荐

