c# - 使用 AutoMapper 将嵌套元素映射到相关列表

标签 c# automapper

我有两组对象

我在 C# 客户端应用程序中使用的对象:

public class EmployeeClient
{
    public int Id { get; set; }

    public int DepartmentId { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string MiddleName { get; set; }
}

public class DepartmentClient
{
    public int Id { get; set; }

    public string Name { get; set; }
}

public class OrganizationClient
{
    public int Id { get; set; }

    public string Name { get; set; }

    public List<DepartmentClient> Departments { get; set; }

    public List<EmployeeClient> Employees { get; set; }
}

和 DTO:

public class EmployeeDto
{
    public int Id { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string MiddleName { get; set; }
}

public class DepartmentDto
{
    public int Id { get; set; }

    public string Name { get; set; }

    public List<EmployeeDto> Employees { get; set; }
}

public class OrganizationDto
{
    public int Id { get; set; }

    public string Name { get; set; }

    public List<DepartmentDto> Departments { get; set; }
}

我使用 AutoMapper,我需要配置映射客户端 -> DTO 和 DTO -> 客户端。 我像这样实现了映射 DTO-> 客户端:

public class DtoToClientMappingProfile: Profile
{
    public DtoToClientMappingProfile()
    {
        CreateMap<EmployeeDto, EmployeeClient>();

        CreateMap<DepartmentDto, DepartmentClient>();

        CreateMap<OrganizationDto, OrganizationClient>()
            .ForMember(dest => dest.Employees, opt => opt.ResolveUsing(src => src.Departments.SelectMany(d => d.Employees)))
            .AfterMap(AfterMap);
    }

    private void AfterMap(OrganizationDto dto, OrganizationClient client)
    {
        foreach (var department in dto.Departments)
        {
            foreach (var employee in department.Employees)
            {
                var clientEmployee = client.Employees.First(e => e.Id == employee.Id);
                clientEmployee.DepartmentId = department.Id;
            }
        }
    }
}

这不是通用的解决方案,但对我有用。

我只找到了一个如何实现映射 Client->DTO 的选项:

public class ClientToDtosMappingProfile : Profile
{
    public ClientToDtosMappingProfile()
    {
        CreateMap<EmployeeClient, EmployeeDto>();

        CreateMap<DepartmentClient, DepartmentDto>();

        CreateMap<OrganizationClient, OrganizationDto>()
            .AfterMap(AfterMap);
    }

    private void AfterMap(OrganizationClient client, OrganizationDto dto)
    {
        foreach (var employee in client.Employees)
        {
            var departmentDto = dto.Departments.First(d => d.Id == employee.DepartmentId);
            if (departmentDto.Employees == null)
            {
                departmentDto.Employees = new List<EmployeeDto>();
            }

            var configuration = (IConfigurationProvider)new MapperConfiguration(cfg =>
            {
                cfg.AddProfiles(typeof(ClientToDtosMappingProfile));
            });

            var mapper = (IMapper)new Mapper(configuration);

            var employeeDto = mapper.Map<EmployeeDto>(employee);
            departmentDto.Employees.Add(employeeDto);
        }
    }
}

它有效,但我不喜欢这个解决方案,因为我每次映射对象时都应该创建新的 Mapper 实例。在我的真实代码中,Employee 有很多嵌套元素,并且映射是在多个配置文件中配置的。

关于如何更好地实现它有什么想法吗?

最佳答案

我使用 ResolutionContext 改进了我的代码。它允许不在 AfterMap 函数中创建映射器。

DtoToClientMappingProfile:

public class DtoToClientMappingProfile: Profile
{
    public DtoToClientMappingProfile()
    {
        CreateMap<EmployeeDto, EmployeeClient>();

        CreateMap<DepartmentDto, DepartmentClient>();

        CreateMap<OrganizationDto, OrganizationClient>()
            .ForMember(dest => dest.Employees, opt => opt.Ignore())
            .AfterMap(AfterMap);
    }

    private void AfterMap(OrganizationDto dto, OrganizationClient client, ResolutionContext resolutionContext)
    {
        if (dto.Departments == null)
        {
            return;
        }

        client.Departments = new List<DepartmentClient>();
        foreach (var department in dto.Departments)
        {
            var departmentClient = resolutionContext.Mapper.Map<DepartmentClient>(department);
            client.Departments.Add(departmentClient);
            if (department.Employees == null)
            {
                continue;
            }

            if (client.Employees == null)
            {
                client.Employees = new List<EmployeeClient>();
            }

            foreach (var employee in department.Employees)
            {
                var employeeClient = resolutionContext.Mapper.Map<EmployeeClient>(employee);
                employeeClient.DepartmentId = department.Id;
                client.Employees.Add(employeeClient);
            }
        }
    }

ClientToDtosMappingProfile:

public class ClientToDtosMappingProfile : Profile
{
    public ClientToDtosMappingProfile()
    {
        CreateMap<EmployeeClient, EmployeeDto>();

        CreateMap<DepartmentClient, DepartmentDto>();

        CreateMap<OrganizationClient, OrganizationDto>()
            .AfterMap(AfterMap);
    }

    private void AfterMap(OrganizationClient client, OrganizationDto dto, ResolutionContext resolutionContext)
    {
        if (client.Employees == null)
        {
            return;
        }

        foreach (var employee in client.Employees)
        {
            var departmentDto = dto.Departments.First(d => d.Id == employee.DepartmentId);
            if (departmentDto.Employees == null)
            {
                departmentDto.Employees = new List<EmployeeDto>();
            }

            var employeeDto = resolutionContext.Mapper.Map<EmployeeDto>(employee);
            departmentDto.Employees.Add(employeeDto);
        }
    }
}

关于c# - 使用 AutoMapper 将嵌套元素映射到相关列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46186129/

相关文章:

c# - 拉伸(stretch)单元格内的内部内容 iText 7 PDF

c# - F# 从 C# 继承类访问 protected 字段

.net - AutoMapper 使用 StructureMap 实例化复杂类型

c# - 如何在asp.net核心中的x单元单元测试中模拟AutoMapper IConfigurationProvider

c# - Automapper UseDestinationValue

c# - .NET CLR 线程池耗尽 - 实现错误?

c# - 未使用 asp.net 下载 Zip 文件

C# Entity Framework 保存 1-1 关系

c# - 在 Automapper 中映射时忽略导航属性

c# - Automapper:如何不重复从复杂类型到基类的映射配置