C#中如何用AutoMapper映射分组统计结果至ViewModel
如何将匿名类型列表映射到StatusDetailsViewModel(AutoMapper或手动方案)
嘿,针对你遇到的这个映射问题,其实有两种实用的解决思路——如果场景简单,直接手动映射反而更高效;如果项目统一用AutoMapper,也可以轻松配置实现自动映射。下面分别拆解:
方案一:手动映射(最直接,无需额外依赖)
你的匿名类型属性和StatusDetailsViewModel的字段完全匹配(Status和CountNo),完全可以在LINQ查询的Select阶段直接创建ViewModel实例,一步到位,省掉后续的映射步骤:
public List<StatusDetailsViewModel> CheckMeetingStatus(long actionId) { var statusDetails = _igniteDb.myTable .Where(a => a.actionId == actionId) .GroupBy(a => new { a.Status, a.ElectionGroup }) .GroupBy(c => new { c.Key.Status}) .Select(b => new StatusDetailsViewModel { Status = b.Key.Status, CountNo = b.Count() }) .ToList(); return statusDetails; }
这种方式代码更简洁,性能也更好,毕竟少了AutoMapper的映射开销,适合这种字段匹配简单的场景。
方案二:用AutoMapper实现自动映射
如果你项目里已经在用AutoMapper,或者需要统一用它处理映射,可以按以下步骤配置:
1. 先装AutoMapper包
确保你的项目已经安装了AutoMapper的NuGet包:
# NuGet包管理器控制台 Install-Package AutoMapper # 或者用.NET CLI dotnet add package AutoMapper
2. 配置映射规则
在项目启动时(比如Program.cs或者专门的映射配置类),添加AutoMapper的映射配置。因为匿名类型和ViewModel的属性名完全一致,AutoMapper可以自动识别匹配,不过因为匿名类型是编译时的临时类型,我们可以用显式配置确保稳妥:
// 方式1:直接在Program.cs中配置(.NET 6+) builder.Services.AddAutoMapper(cfg => { cfg.CreateMap<object, StatusDetailsViewModel>() .ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.GetType().GetProperty("Status").GetValue(src))) .ForMember(dest => dest.CountNo, opt => opt.MapFrom(src => src.GetType().GetProperty("CountNo").GetValue(src))); }); // 方式2:创建单独的Profile配置类(更易维护) public class MappingProfile : Profile { public MappingProfile() { CreateMap<object, StatusDetailsViewModel>() .ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.GetType().GetProperty("Status").GetValue(src))) .ForMember(dest => dest.CountNo, opt => opt.MapFrom(src => src.GetType().GetProperty("CountNo").GetValue(src))); } } // 然后在Program.cs中注册:builder.Services.AddAutoMapper(typeof(MappingProfile));
注:如果你的匿名类型在编译时能被AutoMapper直接识别,其实也可以不用显式指定成员映射,AutoMapper会自动匹配同名属性,上面的显式配置是更稳妥的兜底方案。
3. 在你的方法中使用AutoMapper
通过构造函数注入拿到IMapper实例,然后执行映射:
// 先通过构造函数注入IMapper private readonly IMapper _mapper; public YourServiceClass(IMapper mapper) { _mapper = mapper; } public List<StatusDetailsViewModel> CheckMeetingStatus(long actionId) { var statuses = _igniteDb.myTable .Where(a => a.actionId == actionId) .GroupBy(a => new { a.Status, a.ElectionGroup }) .GroupBy(c => new { c.Key.Status}) .Select(b => new { Status = b.Key.Status, CountNo = b.Count()}) .ToList(); // 用AutoMapper把匿名类型列表转成ViewModel列表 var statusDetails = _mapper.Map<List<StatusDetailsViewModel>>(statuses); return statusDetails; }
小提示
- 映射时要确保匿名类型的属性名和ViewModel的属性名完全一致(大小写敏感),AutoMapper才能正确匹配。
- 推荐用依赖注入来管理
IMapper实例,不要手动创建,这样可以统一维护映射配置,也更符合.NET的最佳实践。
内容的提问来源于stack exchange,提问作者xzk




