Map nested elements to related lists using AutoMapper

一笑奈何 提交于 2019-12-08 14:36:25

I made my code a bit better using ResolutionContext. It allows not to create mappers in AfterMap function.

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);
        }
    }
}

If you call AssertConfigurationIsValid, AM will complain about what it doesn't know how to map.

The problem seems to be that you don't have the information needed to fill the destination object in the source object.

You will need to add a resolver for each property AM complains about, like the ResolveUsing you already have, for example.

You also need to pass the extra information that's needed.

The result may not look good eventually because AM cannot rely on uniform objects to do its job, you have to tell it what to do.

Another way to go about it is to do the high level mapping in your own code and rely on AM only when the mapping is simple enough so AM can do it by itself. The more you customize AM, the less value you get from it.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!