AutoMapper条件实体映射

4
我有一个数据库实体,用于存储订单地址,如下所示...

enter image description here

我有以下BLL类...
public class DeliveryAddress
{
    public string Id { get; set; }
    public string PersonyName { get; set; }
    public string CompanyName { get; set; }
    public List<string> AddressLines { get; set; }
    public string Zip { get; set; }
    public string City { get; set; }
    public string CountryCode { get; set; }
}

和另一个类似的课程...
public class InvoiceAddress
{
    public string Id { get; set; }
    public string PersonyName { get; set; }
    public string CompanyName { get; set; }
    public List<string> AddressLines { get; set; }
    public string Zip { get; set; }
    public string City { get; set; }
    public string CountryCode { get; set; }
}

我想根据AddressType列将EF实体映射到上述类。有人可以解释一下如何做吗?
更新:
如果addressType为“Delivery”,则要映射到OR.DeliveryAddress,如果addressType为“Invoice”,则要映射到OR.InvoiceAddress。
到目前为止,我已经能够做到这一点,但我不知道如何在实体映射级别应用条件...
Mapper.CreateMap<OrderAddress, OR.DeliveryAddress>()
       .ForMember(d => d.City, o => o.MapFrom(s => s.city))
       .ForMember(d => d.CompanyName, o => o.UseValue(string.Empty))
       .ForMember(d => d.CountryCode, o => o.MapFrom(s => s.countryCode))
       .ForMember(d => d.Id, o => o.MapFrom(s => s.id))
       .ForMember(d => d.PersonyName, o => o.MapFrom(s => s.name))
       .ForMember(d => d.Zip, o => o.MapFrom(s => s.zip));

更新2:
与@Yuliam讨论后,这是我为我的问题想出来的Fiddle

如果地址类型为“Delivery”,您是否想要映射到OR.DeliveryAddress,如果地址类型为“Invoice”,您是否想要映射到OR.InvoiceAddress - Yuliam Chandra
没错,你说得对... - Naveed Butt
我认为你不应该在这里使用子类型,而是复制地址类型。AutoMapper没有针对此的工具。 - Gert Arnold
@GertArnold 你说的不使用子类型是什么意思? - Naveed Butt
啊,它们不是子类型。好吧,只需使用一个类型,包括一个地址类型属性即可。 - Gert Arnold
我不能。这是我从其他开发人员继承的代码,我无法更改代码结构... - Naveed Butt
2个回答

2
你可以创建一个自定义的对象映射器。如果属性名称只是大小写不同(除了 PersonName),则不必使用 ForMember 指定每个属性,因为默认情况下,AutoMapper 在映射属性名称时是不区分大小写的。请保留 HTML 标签。
public class AddressConverter : ITypeConverter<OrderAddress, object>
{
    public object Convert(ResolutionContext context)
    {
        var o = context.SourceValue as OrderAddress;
        if (o == null) return null;

        if (o.addressType == "Delivery") return Mapper.Map<OR.DeliveryAddress>(o);
        if (o.addressType == "Invoice") return Mapper.Map<OR.InvoiceAddress>(o);
        return null;
    }
}

然后定义映射器。
Mapper.CreateMap<OrderAddress, OR.DeliveryAddress>()
    .ForMember(d => d.PersonyName, o => o.MapFrom(s => s.name));
Mapper.CreateMap<OrderAddress, OR.InvoiceAddress>()
    .ForMember(d => d.PersonyName, o => o.MapFrom(s => s.name));
Mapper.CreateMap<OrderAddress, object>().ConvertUsing<AddressConverter>();

用法。

var orderAddressDto = Mapper.Map<object>(orderAddress);

实际的orderAddressDto类型将基于addressType。如果您有OR.DeliveryAddressOR.InvoiceAddress的接口或基类,那么将更加强类型化。然后用接口/基类替换对象类型。


我尝试了这个方法,但是没有成功,所以没有采纳你的答案。我还在继续寻找答案。我最终使用了Linq查询来手动填充对象... - Naveed Butt
@NaveedButt,你是直接映射订单地址还是从订单中映射的?你是怎么映射的? - Yuliam Chandra
@NaveedButt,在这个问题中没有使用到map,只有配置,让我再澄清一下,你是使用了 var orderAddressDto = Mapper.Map<object>(orderAddress) 还是 var orderDto = Mapper.Map<object>(order) 还是 var addressesDto = Mapper.Map<object[]>(order.OrderAddresses) 或者其他什么方法? - Yuliam Chandra
@NaveedButt,这里运行良好链接,可能是您那边缺少了一些正确配置或错误使用。 - Yuliam Chandra
让我们继续在聊天中讨论 - Yuliam Chandra
显示剩余4条评论

0

你可能想要尝试查看ResolveUsing

这是半伪代码,因为我不知道你的整个领域模型是什么样子:

Mapper.CreateMap<OrderObject, OrderDto>()
    .ForMember(x => x.Address, opt => opt.ResolveUsing(oo => oo.Type == Invoice ? oo.InvoiceAddress : oo.DeliveryAddress));

我在这里假设您有一个实际的Order实体,您正在尝试将其转化为仅包含一个地址字段的'OrderDto'。


在订单实体中有一个List<OrderAddress>。这是将实体转换为DTO的方法。那么,将DTO转换回实体的方法是什么呢?我想我需要使用Yuliam的方法,对吗? - Naveed Butt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接