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

如何使用AutoMapper对相似项分组并实现双向映射?

使用AutoMapper实现分组合并映射及双向映射方案

这个需求核心是按AppName和Role对Source集合分组,把同组的UserName和Action分别合并成列表,同时还要支持双向映射。我来一步步拆解实现方案:

一、单向映射(Source集合 → Destination集合)

首先得先对Source做分组,因为AutoMapper是对象到对象的映射工具,我们需要把每个分组转换成对应的Destination对象。

1. 配置AutoMapper映射规则

创建一个Profile类,专门定义这两个类型的映射逻辑:

public class SourceDestinationProfile : Profile
{
    public SourceDestinationProfile()
    {
        // 配置从分组对象到Destination的映射
        CreateMap<IGrouping<(string AppName, string Role), Source>, Destination>()
            // 从分组里提取所有UserName,转成列表赋值给UserNames
            .ForMember(dest => dest.UserNames, opt => opt.MapFrom(src => src.Select(s => s.UserName).ToList()))
            // 同理提取所有Action转成列表
            .ForMember(dest => dest.Actions, opt => opt.MapFrom(src => src.Select(s => s.Action).ToList()))
            // 分组的Key里已经包含了唯一的AppName和Role,直接取就行(同组元素这两个字段肯定一致)
            .ForMember(dest => dest.AppName, opt => opt.MapFrom(src => src.Key.AppName))
            .ForMember(dest => dest.Role, opt => opt.MapFrom(src => src.Key.Role));
    }
}

2. 执行映射流程

先初始化AutoMapper,然后对Source集合分组,最后完成映射:

// 项目启动时只需要配置一次AutoMapper
var config = new MapperConfiguration(cfg => cfg.AddProfile<SourceDestinationProfile>());
var mapper = config.CreateMapper();

// 你的示例Source集合
var sources = new List<Source>
{
    new Source { UserName = "John", AppName = "MyApplication", Role = "Admin", Action = "Add" },
    new Source { UserName = "Elis", AppName = "MyApplication", Role = "Admin", Action = "Edit" }
};

// 按AppName和Role分组,确保同组的元素这两个字段完全一致
var groupedSources = sources.GroupBy(s => (s.AppName, s.Role));

// 把分组后的集合映射成Destination列表
var destinations = mapper.Map<List<Destination>>(groupedSources);

运行这段代码后,就能得到你期望的结果:单个Destination对象,UserNames包含["John", "Elis"],Actions包含["Add", "Edit"],AppName和Role保持为"MyApplication"和"Admin"。

二、双向映射(Destination → Source集合)

反向映射需要把一个Destination对象还原成多个Source对象,但这里有个需要注意的点:当前的Destination结构丢失了用户与动作的关联关系(比如不知道John对应Add还是Edit)。如果你的业务场景是同一组的所有用户都拥有该组的所有动作,那我们可以生成所有用户-动作的组合;如果需要精准还原原始的Source集合,那可能需要调整Destination的结构(比如新增子对象保存用户和动作的对应关系)。

1. 添加反向映射规则

在之前的Profile里补充反向映射的自定义转换逻辑:

public class SourceDestinationProfile : Profile
{
    public SourceDestinationProfile()
    {
        // 正向映射(分组→Destination)
        CreateMap<IGrouping<(string AppName, string Role), Source>, Destination>()
            .ForMember(dest => dest.UserNames, opt => opt.MapFrom(src => src.Select(s => s.UserName).ToList()))
            .ForMember(dest => dest.Actions, opt => opt.MapFrom(src => src.Select(s => s.Action).ToList()))
            .ForMember(dest => dest.AppName, opt => opt.MapFrom(src => src.Key.AppName))
            .ForMember(dest => dest.Role, opt => opt.MapFrom(src => src.Key.Role));

        // 反向映射(Destination→Source集合)
        CreateMap<Destination, IEnumerable<Source>>()
            .ConvertUsing(dest => 
                // 将每个UserName和每个Action组合,生成对应的Source对象
                dest.UserNames.SelectMany(userName => 
                    dest.Actions.Select(action => 
                        new Source 
                        { 
                            UserName = userName, 
                            AppName = dest.AppName, 
                            Role = dest.Role, 
                            Action = action 
                        })));
    }
}

2. 执行反向映射

直接把Destination对象传给AutoMapper,就能得到对应的Source集合:

// 示例Destination对象
var destination = new Destination
{
    UserNames = new List<string> { "John", "Elis" },
    AppName = "MyApplication",
    Role = "Admin",
    Actions = new List<string> { "Add", "Edit" }
};

// 反向映射得到Source列表
var sources = mapper.Map<List<Source>>(destination);

这段代码会生成4个Source对象:John-Add、John-Edit、Elis-Add、Elis-Edit。如果你的业务场景需要精准还原原始的2条记录,那建议调整Destination结构,比如用List<UserActionPair>代替分开的UserNames和Actions,这样反向映射时就能准确对应关系。

内容的提问来源于stack exchange,提问作者Денис Дягилев

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:12:31