使用AutoMapper将简单DTP转换为复杂DTO

时间:2019-12-17 14:52:36

标签: c# automapper

我有一个简单的DTO,如下所示:

    public partial class Company
    {
        public string NAME { get; set; }        

        public string CONTACT_ADDR1_1 { get; set; }
        public string CONTACT_ADDR2_1 { get; set; }
        public string CONTACT_CITY_1 { get; set; }
        public string CONTACT_STATE_1 { get; set; }
        public string CONTACT_ZIP_1 { get; set; }

        public string CONTACT_ADDR1_2 { get; set; }
        public string CONTACT_ADDR2_2 { get; set; }
        public string CONTACT_CITY_2 { get; set; }
        public string CONTACT_STATE_2 { get; set; }
        public string CONTACT_ZIP_2 { get; set; }

        public string CONTACT_ADDR1_3 { get; set; }
        public string CONTACT_ADDR2_3 { get; set; }
        public string CONTACT_CITY_3 { get; set; }
        public string CONTACT_STATE_3 { get; set; }
        public string CONTACT_ZIP_3 { get; set; }
     }

我想使用AutoMapper将其转换为具有类型列表的Company对象。我将有一个已知的地址数(6)。我只列出了三个。

    public partial class CompanyDto
    {
        public string NAME { get; set; }
        public List<AddressDto> { get; set; }
     }

    public partial class AddressDto
    {
        public string CONTACT_ADDR1 { get; set; }
        public string CONTACT_ADDR2 { get; set; }
        public string CONTACT_CITY { get; set; }
        public string CONTACT_STATE { get; set; }
        public string CONTACT_ZIP { get; set; }
     }

这是我遇到的困难的代码块:

cfg.CreateMap<Company, CompanyDto>();

3 个答案:

答案 0 :(得分:3)

我不建议为此使用pid := 7880 loops := 20 time_dll := 0 Loop, % loops { QPC(1) tree_dll := processTree(pid) time_dll += QPC() } time_dll /= loops time_wmi := 0 Loop, % loops { QPC(1) tree_wmi := processTree(pid, True) time_wmi += QPC() } time_wmi /= loops MsgBox,,>, % "DLL: " time_dll "`nWMI: " time_wmi ;------------------------------------------------------------------------------- processTree(pid, wmi := False, obj := False) { Local tree := [] If wmi { If !obj obj := ComObjGet("winmgmts:").ExecQuery("SELECT ProcessId,ParentProcessId FROM Win32_Process") tree := [] For result in obj If pid = result.ParentProcessId { tree.Push(result.ProcessId) subs := %A_ThisFunc%(result.ProcessId, True, obj) For idx,val in subs tree.Push(val) } } Else { Static MAX_PATH := 260 << !!A_IsUnicode Static varCapacity := MAX_PATH VarSetCapacity(lppe, varCapacity) NumPut(varCapacity, lppe, "UInt") hSnapshot := DllCall("CreateToolhelp32Snapshot", "UInt",0x2, "UInt",pid, "Ptr") DllCall("Process32First", "Ptr",hSnapshot, "Ptr",&lppe) Loop { parent := NumGet(lppe, 16 + A_PtrSize * 2, "UInt") If (parent = pid) { child := NumGet(lppe, 8, "UInt") tree.Push(child) gchilds := %A_ThisFunc%(child) For idx,val in gchilds tree.Push(val) } } Until !DllCall("Process32Next", "Ptr",hSnapshot, "Ptr",&lppe) DllCall("CloseHandle", "Ptr",hSnapshot) } Return, tree } QPC(start := 0) { Static P := 0, F := 0, Q := DllCall("QueryPerformanceFrequency", "Int64P",F) Return !DllCall("QueryPerformanceCounter", "Int64P",Q) + (start ? (P:=Q)/F : (Q-P)/F) }

花2分钟时间输入一次,最多不会花10分钟。我建议创建扩展方法并为复杂的映射转换您自己的DTO。通过第三方库进行配置将为您省去很多麻烦。

automapper

答案 1 :(得分:3)

        CreateMap<Company, CompanyDto>()
            .AfterMap((s, d) =>
            {
                d.ADDRESSES = new System.Collections.Generic.List<AddressDto>();
                d.ADDRESSES.Add(new AddressDto
                {
                    CONTACT_ADDR1 = s.CONTACT_ADDR1_1,
                    CONTACT_ADDR2 = s.CONTACT_ADDR1_2,
                    CONTACT_CITY = s.CONTACT_CITY_1,
                    CONTACT_STATE = s.CONTACT_STATE_1,
                    CONTACT_ZIP = s.CONTACT_ZIP_1
                });
                d.ADDRESSES.Add(new AddressDto
                {
                    CONTACT_ADDR1 = s.CONTACT_ADDR2_1,
                    CONTACT_ADDR2 = s.CONTACT_ADDR2_2,
                    CONTACT_CITY = s.CONTACT_CITY_2,
                    CONTACT_STATE = s.CONTACT_STATE_2,
                    CONTACT_ZIP = s.CONTACT_ZIP_2
                });
            });

以上可能有效(并重复输入您拥有的地址数量)。我必须承认我实际上并没有运行此代码,但是看起来可以通过

答案 2 :(得分:1)

我更喜欢@Train的答案,因为它是一种更易理解的方法,它也更容易调试和排除故障。

但是如果AutoMapper是强制性的,则可以使用Custom Value Resolver,例如喜欢:

public class CompanyToCompanyDtoResolver : IValueResolver<Company, CompanyDto, List<AddressDto>>
{            
    public List<AddressDto> Resolve(Company source, CompanyDto destination, List<AddressDto> destMember, ResolutionContext context)
    {
        var contacts = new List<AddressDto>();

        var companyType = typeof(Company);

        for (int i = 1; i <= 6; i++)
        {
            var address = new AddressDto();

            address.CONTACT_ADDR1 = (string)companyType
                .GetProperty(nameof(Company.CONTACT_ADDR1_1).Replace("_1", $"_{i}"))
                .GetValue(source);

            address.CONTACT_ADDR2 = (string)companyType
                .GetProperty(nameof(Company.CONTACT_ADDR2_1).Replace("_1", $"_{i}"))
                .GetValue(source);

            address.CONTACT_CITY = (string)companyType
                .GetProperty(nameof(Company.CONTACT_CITY_1).Replace("_1", $"_{i}"))
                .GetValue(source);

            address.CONTACT_STATE = (string)companyType
                .GetProperty(nameof(Company.CONTACT_STATE_1).Replace("_1", $"_{i}"))
                .GetValue(source);

            address.CONTACT_ZIP = (string)companyType
                .GetProperty(nameof(Company.CONTACT_ZIP_1).Replace("_1", $"_{i}"))
                .GetValue(source);

            contacts.Add(address);
        }

        return contacts;
    }
}

...

    cfg.CreateMap<Company, CompanyDto>()
       .ForMember(destination => destination.Contacts, 
                  source => source.MapFrom<CompanyToCompanyDtoResolver>());