使用 AutoMapper 将简单 DTP 转换为复杂 DTO
Convert Simple DTP into Complex DTO using 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 将其转换为具有类型列表的公司对象。我将拥有已知数量的地址 (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>();
我不建议为此使用 automapper
。
我花了 2 分钟打完这个,你不会超过 10 分钟。我建议创建扩展方法并为复杂映射转换您自己的 DTO。尝试通过第三方库配置它会让你省去很多麻烦。
public static class CompanyExtensions{
public static CompanyDto ToCompanyDto(this Company c){
var cDto = new CompanyDto();
cDto.Name = c.Name;
cDto.Addresses = new List<AddressDto>();
cDto.Addresses.Add(c.ToAddress1Dto());
cDto.Addresses.Add(c.ToAddress2Dto());
...
return cDto;
}
public static AddressDto ToCopmanyAddress1Dto(this Company c){
return new AddressDto()
{
CONTACT_ADDR1 = c.CONTACT_ADDR1,
CONTACT_ADDR2 = c.CONTACT_ADDR2,
CONTACT_CITY = c.CONTACT_CITY,
CONTACT_STATE = c.CONTACT_STATE,
CONTACT_ZIP = c.CONTACT_ZIP
}
}
public static AddressDto ToCopmanyAddress2Dto(this Company c){
...
}
... for the other addresses
}
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
});
});
以上可能有效(并根据您拥有的地址数量重复)。我必须承认我实际上没有 运行 这个代码,但它看起来还过得去
我更喜欢@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>());
我有一个简单的 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 将其转换为具有类型列表的公司对象。我将拥有已知数量的地址 (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>();
我不建议为此使用 automapper
。
我花了 2 分钟打完这个,你不会超过 10 分钟。我建议创建扩展方法并为复杂映射转换您自己的 DTO。尝试通过第三方库配置它会让你省去很多麻烦。
public static class CompanyExtensions{
public static CompanyDto ToCompanyDto(this Company c){
var cDto = new CompanyDto();
cDto.Name = c.Name;
cDto.Addresses = new List<AddressDto>();
cDto.Addresses.Add(c.ToAddress1Dto());
cDto.Addresses.Add(c.ToAddress2Dto());
...
return cDto;
}
public static AddressDto ToCopmanyAddress1Dto(this Company c){
return new AddressDto()
{
CONTACT_ADDR1 = c.CONTACT_ADDR1,
CONTACT_ADDR2 = c.CONTACT_ADDR2,
CONTACT_CITY = c.CONTACT_CITY,
CONTACT_STATE = c.CONTACT_STATE,
CONTACT_ZIP = c.CONTACT_ZIP
}
}
public static AddressDto ToCopmanyAddress2Dto(this Company c){
...
}
... for the other addresses
}
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
});
});
以上可能有效(并根据您拥有的地址数量重复)。我必须承认我实际上没有 运行 这个代码,但它看起来还过得去
我更喜欢@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>());