映射到不同的对象,具体取决于子集合

时间:2016-12-02 14:58:25

标签: c# xml automapper

我目前正在处理的项目要求我将几个(XML)对象映射到不同的对象。为了让我的生活更轻松,我决定将AutoMapper用于此目的,并且它在促进所需功能方面做得很好。

然而,有一个我正在努力的映射。

首先,让我向您提供我们从客户处收到的XML:

<OURCOMPANY_ETA>        
    ...
    <ROUTE_ACTIONS> 
        <TRIP>1294783</TRIP>
        <SHIPMENT_NO>6483</SHIPMENT_NO>
        <ACTION_TYPE>SomeOtherAction</ACTION_TYPE >
        <ETA_DATE>2016-10-24</ETA_DATE>
        <ETA_TIME>22:22</ETA_TIME>
    </ROUTE_ACTIONS>    
    ... 
</OURCOMPANY_ETA>       

这应该转换为如下所示的对象:

<?xml version="1.0" encoding="UTF-8"?>          
<OURCOMPANY_ETA>            
    ..
    <SHIPMENTS>     
        <SHIPMENT>  
            <OURCOMPANYID>6483/1294783</OURCOMPANYID>
            <ACTION_TYPE>SomeOtherAction</ACTION_TYPE>
            <EDA>2016-10-24</EDA>
            <ETA>22:22</ETA>
        </SHIPMENT> 
    </SHIPMENTS>
    ...
</OURCOMPANY_ETA>

您可能已经注意到客户有一个名为ROUTE_ACTIONS的元素。此元素不是您所期望的ROUTE_ACTION元素的集合,而只是包含某些数据的单个节点。 我们自己的XML包含一个SHIPMENTS节点,其子节点称为SHIPMENT。这些SHIPMENT节点与ROUTE_ACTIONS

很好地匹配

将客户对象映射到我们自己的对象是非常可行的。我们只创建一个只有1 SHIPMENTS个节点的新SHIPMENT节点,一切正常。 但是,当从我们自己的对象移回客户的对象时会出现问题。客户无法处理集合,因此我们必须为自己对象中的每个SHIPMENT节点创建一个新对象。

给出以下XML

...
<SHIPMENTS>     
    <SHIPMENT>  
        <OURCOMPANYID>6483/1294783</OURCOMPANYID>
        <ACTION_TYPE>SomeOtherAction</ACTION_TYPE>
        <EDA>2016-10-24</EDA>
        <ETA>22:22</ETA>
    </SHIPMENT> 
    <SHIPMENT>  
        <OURCOMPANYID>3123/47348236</OURCOMPANYID>
        <ACTION_TYPE>SomeAction</ACTION_TYPE>
        <EDA>2016-10-24</EDA>
        <ETA>22:22</ETA>
    </SHIPMENT> 
</SHIPMENTS>
...

我们必须创建2个对象,类似于:

<OURCOMPANY_ETA>        
    ...
    <ROUTE_ACTIONS> 
        <TRIP>1294783</TRIP>
        <SHIPMENT_NO>6483</SHIPMENT_NO>
        <ACTION_TYPE>SomeOtherAction</ACTION_TYPE >
        <ETA_DATE>2016-10-24</ETA_DATE>
        <ETA_TIME>22:22</ETA_TIME>
    </ROUTE_ACTIONS>    
    ...
</OURCOMPANY_ETA>       
<!--And another object-->
<OURCOMPANY_ETA>        
    ...
    <ROUTE_ACTIONS> 
        <TRIP>47348236</TRIP>
        <SHIPMENT_NO>3123</SHIPMENT_NO>
        <ACTION_TYPE>SomeAction</ACTION_TYPE >
        <ETA_DATE>2016-10-24</ETA_DATE>
        <ETA_TIME>22:22</ETA_TIME>
    </ROUTE_ACTIONS>
    ...
</OURCOMPANY_ETA>

有关如何使用AutoMapper处理此问题的任何想法?如果无法直接执行此操作,是否可以创建自己的逻辑并仍然使用AutoMapping来调用此逻辑,就像使用IValueResolver一样?

我使用Visual Studio将XML粘贴到对象来生成对象。为了完整起见,可以在本文末尾找到它们。一开始没有添加它们,因为它们非常大。

我到目前为止创建的映射如下:

CreateMap<Convertor.Customer.Model.Eta.OURCOMPANY_ETA, Convertor.Model.OURCOMPANY.Eta.OURCOMPANY_ETA>()
        .ForMember(ed => ed.TIMESTAMP, opt => opt.MapFrom(es => es.DATETIME_CREATED))
        .ForMember(ed => ed.SHIPMENTS, opt => opt.MapFrom(es => es.ROUTE_ACTIONS))
        .ForMember(ed => ed.SUBCONTRACTOR_CODE, opt => opt.Ignore())
        .AfterMap((src, dest) => dest.VERSION = new decimal(2.0)); 
    CreateMap<Convertor.Model.OURCOMPANY.Eta.OURCOMPANY_ETA, Convertor.Customer.Model.Eta.OURCOMPANY_ETA>()
        .ForMember(ed => ed.DATETIME_CREATED, opt => opt.MapFrom(es => es.TIMESTAMP))
        .ForMember(ed => ed.ROUTE_ACTIONS, opt => opt.MapFrom(es => es.SHIPMENTS))
        .AfterMap((src, dest) => dest.VERSION = new decimal(1.3));

CreateMap<Convertor.Customer.Model.Eta.OURCOMPANY_ETAROUTE_ACTIONS, Convertor.Model.OURCOMPANY.Eta.OURCOMPANY_ETASHIPMENT>()
        .ForMember(ed => ed.OURCOMPANYID, opt => opt.ResolveUsing<EtaValueResolvers.GenerateOURCOMPANYId>());

    CreateMap<Convertor.Model.OURCOMPANY.Eta.OURCOMPANY_ETASHIPMENT, Convertor.Customer.Model.Eta.OURCOMPANY_ETAROUTE_ACTIONS>()
        .ForMember(ed => ed.SHIPMENT_NO, opt => opt.ResolveUsing<EtaValueResolvers.ExtractShipmentOURCOMPANYId>())
        .ForMember(ed => ed.TRIP, opt => opt.ResolveUsing<EtaValueResolvers.ExtractTripOURCOMPANYId>());

我们公司的目标是这样的:

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class OURCOMPANY_ETA
{

    private System.DateTime tIMESTAMPField;

    private string sUBCONTRACTOR_NAMEField;

    private string sUBCONTRACTOR_CODEField;

    private string OURCOMPANYCOMPANYField;

    private decimal vERSIONField;

    private OURCOMPANY_ETASHIPMENT[] sHIPMENTSField;

    /// <remarks/>
    public System.DateTime TIMESTAMP
    {
        get
        {
            return this.tIMESTAMPField;
        }
        set
        {
            this.tIMESTAMPField = value;
        }
    }

    /// <remarks/>
    public string SUBCONTRACTOR_NAME
    {
        get
        {
            return this.sUBCONTRACTOR_NAMEField;
        }
        set
        {
            this.sUBCONTRACTOR_NAMEField = value;
        }
    }

    /// <remarks/>
    public string SUBCONTRACTOR_CODE
    {
        get
        {
            return this.sUBCONTRACTOR_CODEField;
        }
        set
        {
            this.sUBCONTRACTOR_CODEField = value;
        }
    }

    /// <remarks/>
    public string OURCOMPANYCOMPANY
    {
        get
        {
            return this.OURCOMPANYCOMPANYField;
        }
        set
        {
            this.OURCOMPANYCOMPANYField = value;
        }
    }

    /// <remarks/>
    public decimal VERSION
    {
        get
        {
            return this.vERSIONField;
        }
        set
        {
            this.vERSIONField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlArrayItemAttribute("SHIPMENT", IsNullable = false)]
    public OURCOMPANY_ETASHIPMENT[] SHIPMENTS
    {
        get
        {
            return this.sHIPMENTSField;
        }
        set
        {
            this.sHIPMENTSField = value;
        }
    }
}

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class OURCOMPANY_ETASHIPMENT
{

    private string OURCOMPANYIDField;

    private string aCTION_TYPEField;

    private System.DateTime eDAField;

    private string eTAField;

    /// <remarks/>
    public string OURCOMPANYID
    {
        get
        {
            return this.OURCOMPANYIDField;
        }
        set
        {
            this.OURCOMPANYIDField = value;
        }
    }

    /// <remarks/>
    public string ACTION_TYPE
    {
        get
        {
            return this.aCTION_TYPEField;
        }
        set
        {
            this.aCTION_TYPEField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(DataType = "date")]
    public System.DateTime EDA
    {
        get
        {
            return this.eDAField;
        }
        set
        {
            this.eDAField = value;
        }
    }

    /// <remarks/>
    public string ETA
    {
        get
        {
            return this.eTAField;
        }
        set
        {
            this.eTAField = value;
        }
    }
}

客户的目标是这样的:

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class OURCOMPANY_ETA
{

    private System.DateTime dATETIME_CREATEDField;

    private string cHARTERCODEField;

    private string OURCOMPANY_COMPANYField;

    private decimal vERSIONField;

    private OURCOMPANY_ETAROUTE_ACTIONS rOUTE_ACTIONSField;

    /// <remarks/>
    public System.DateTime DATETIME_CREATED
    {
        get
        {
            return this.dATETIME_CREATEDField;
        }
        set
        {
            this.dATETIME_CREATEDField = value;
        }
    }

    /// <remarks/>
    public string CHARTERCODE
    {
        get
        {
            return this.cHARTERCODEField;
        }
        set
        {
            this.cHARTERCODEField = value;
        }
    }

    /// <remarks/>
    public string OURCOMPANY_COMPANY
    {
        get
        {
            return this.OURCOMPANY_COMPANYField;
        }
        set
        {
            this.OURCOMPANY_COMPANYField = value;
        }
    }

    /// <remarks/>
    public decimal VERSION
    {
        get
        {
            return this.vERSIONField;
        }
        set
        {
            this.vERSIONField = value;
        }
    }

    /// <remarks/>
    public OURCOMPANY_ETAROUTE_ACTIONS ROUTE_ACTIONS
    {
        get
        {
            return this.rOUTE_ACTIONSField;
        }
        set
        {
            this.rOUTE_ACTIONSField = value;
        }
    }
}

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class OURCOMPANY_ETAROUTE_ACTIONS
{

    private string tRIPField;

    private string sHIPMENT_NOField;

    private string aCTION_TYPEField;

    private System.DateTime eTA_DATEField;

    private string eTA_TIMEField;

    /// <remarks/>
    public string TRIP
    {
        get
        {
            return this.tRIPField;
        }
        set
        {
            this.tRIPField = value;
        }
    }

    /// <remarks/>
    public string SHIPMENT_NO
    {
        get
        {
            return this.sHIPMENT_NOField;
        }
        set
        {
            this.sHIPMENT_NOField = value;
        }
    }

    /// <remarks/>
    public string ACTION_TYPE
    {
        get
        {
            return this.aCTION_TYPEField;
        }
        set
        {
            this.aCTION_TYPEField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(DataType = "date")]
    public System.DateTime ETA_DATE
    {
        get
        {
            return this.eTA_DATEField;
        }
        set
        {
            this.eTA_DATEField = value;
        }
    }

    /// <remarks/>
    public string ETA_TIME
    {
        get
        {
            return this.eTA_TIMEField;
        }
        set
        {
            this.eTA_TIMEField = value;
        }
    }
}

1 个答案:

答案 0 :(得分:0)

为了分享我对这个问题的了解,这是我到目前为止所提出的,它似乎正在发挥作用。我不会将其标记为确定的答案,因为有人可能会想出一个更好,更优雅的解决方案。

我所做的是最终使用ITypeConverter,其中一个人拥有对象的最终控制权。但是,该解决方案不再与AutoMapper相关,除了仍然使用库进行映射。

public class OurCompanyEtaToCustomerObjectsConvertor : ITypeConverter<Convertor.Model.OurCompany.Eta.OurCompany_ETA, Eta.OurCompany_ETA[]>
{
    public Customer.Model.Eta.OurCompany_ETA[] Convert(Convertor.Model.OurCompany.Eta.OurCompany_ETA source, Customer.Model.Eta.OurCompany_ETA[] destination, ResolutionContext context)
    {
        destination = new Eta.OurCompany_ETA[0];
        if (source != null)
        {
            if (source.SHIPMENTS != null)
            {
                foreach (var OurCompanyEtashipment in source.SHIPMENTS)
                {
                    var CustomerModel = new Customer.Model.Eta.OurCompany_ETA();
                    //Other stuff....
                    destination = destination.Concat(new[] {CustomerModel}).ToArray();
                }
            }                       
        }
        return destination;
    }
}

地图看起来像这样:

CreateMap<Convertor.Model.OurCompany.Eta.OurCompany_ETA, Convertor.Customer.Model.Eta.OurCompany_ETA[]>()
            .ConvertUsing(new EtaValueResolvers.OurCompanyEtaToCustomerObjectsConvertor());

您可能会注意到我还必须将Destination模型更改为数组才能使用类型转换器。 它可能不是一个非常优雅的解决方案,但我想不出别的东西,仍然使用AutoMapper。

继续使用AutoMapper的主要原因是因为它对我们的其他50多个对象做得很好。这是我们努力的唯一对象,我不想改变我们的通用代码库,只是为了这个单一的异常。