配置AutoMapper映射規則《轉》

來源:互聯網
上載者:User

標籤:ida   程式   bar   code   isp   name   例子   erp   內建   

 


配置AutoMapper映射規則

AutoMapper是基於約定的,因此在實用映射之前,我們需要先進行映射規則的配置。

public class Source{    public int SomeValue { get; set; }    public string AnotherValue { get; set; }}public class Destination{    public int SomeValue { get; set; }}

在上面的代碼中,我們定義了兩個類,我們需要將Source類的對象映射到Destination類的對象上面。要完成這個操作,我們需要對AutoMapper進行如下配置:

Mapper.CreateMap<Source, Destination>();

進行一下測試:

Source src = new Source() { SomeValue = 1, AnotherValue = "2" };Destination dest = Mapper.Map<Destination>(src);ObjectDumper.Write(dest);

我們可以在控制台看到dest對象的屬性值:

這樣我們就完成了一個簡單的AutoMapper映射。

Profile的用法

Profile提供了一個命名的映射類,所有繼承自Profile類的子類都是一個映射集合。

我們來看一下Profile的用法,這個例子中仍然使用上面的Source類和Destination類。

public class SourceProfile : Profile{    protected override void Configure()    {        CreateMap<Source, Destination>();    }}

我們可以再Profile中重寫Configure方法,從而完成映射規則的配置。從Profile初始化Mapper規則:

Mapper.Initialize(x => x.AddProfile<SourceProfile>());

在一個Profile中,我們可以完成多個、更複雜的規則的約定:

public class Destination2{    public int SomeValue { get; set; }    public string AnotherValue2 { get; set; }}public class SourceProfile : Profile{    protected override void Configure()    {        //Source->Destination        CreateMap<Source, Destination>();        //Source->Destination2        CreateMap<Source, Destination2>().ForMember(d => d.AnotherValue2, opt =>        {            opt.MapFrom(s => s.AnotherValue);        });    }}

 

AutoMapper最佳實務

這段內容將討論AutoMapper的規則寫在什麼地方的問題。

在上一段中,我們已經知道了如何使用AutoMapper進行簡單的對象映射,但是,在實際的項目中,我們會有很多類進行映射(從Entity轉換為Dto,或者從Entity轉換為ViewModel等),這麼多的映射如何組織將成為一個問題。

首先我們需要定義一個Configuration.cs的類,該類提供AutoMapper規則配置的入口,它只提供一個靜態方法,在程式第一次啟動並執行時候調用該方法完成配置。

當有多個Profile的時候,我們可以這樣添加:

public class Configuration{    public static void Configure()    {        Mapper.Initialize(cfg =>        {            cfg.AddProfile<Profiles.SourceProfile>();            cfg.AddProfile<Profiles.OrderProfile>();            cfg.AddProfile<Profiles.CalendarEventProfile>();        });    }}

在程式啟動並執行時候,只需要調用Configure方法即可。

瞭解了這些實現以後,我們可以再項目中添加AutoMapper檔案夾,檔案夾結構如下:

Configuration為我們的靜態配置入口類;Profiles檔案夾為我們所有Profile類的檔案夾。如果是MVC,我們需要在Global中調用:

AutoMapper.Configuration.Configure();
扁平化映射(Flattening)

預設情況下,我們的Source類和Destination類是根據屬性名稱進行匹配映射的。除此之外,預設的映射規則還有下面兩種情況,我們稱之為扁平化映射,即當Source類中不包含Destination類中的屬性的時候,AutoMapper會將Destination類中的屬性進行分割,或匹配“Get”開頭的方法,例如:

Order類:

public class Order{    public Customer Customer { get; set; }    public decimal GetTotal()    {        return 100M;    }}

Order類中包含了一個customer對象和一個GetTotal方法,為了方便示範,我直接將GetTotal方法返回100;

Customer類的定義如下:

public class Customer{    public string Name { get; set; }}

OrderDto類的定義如下:

public class OrderDto{    public string CustomerName { get; set; }    public string Total { get; set; }}

我們在進行映射的時候,不需要進行特殊的配置,既可以完成從Order到OrderDto的映射。

public class OrderProfile : Profile{    protected override void Configure()    {        CreateMap<Entity.Order, Dto.OrderDto>();    }}

測試代碼:

Entity.Customer customer = new Entity.Customer() { Name = "Tom" };Entity.Order order = new Entity.Order() { Customer = customer };Dto.OrderDto orderDto = Mapper.Map<Dto.OrderDto>(order);ObjectDumper.Write(order, 2);ObjectDumper.Write(orderDto);

測試結果:

指定映射欄位(Projection)

在實際的業務環境中,我們的Source類和Destination類的欄位不可能一對一的匹配,這個時候我們就需要來指定他們的實際映射關係,例如:

public class CalendarEvent{    public DateTime Date { get; set; }    public string Title { get; set; }}public class CalendarEventForm{    public DateTime EventDate { get; set; }    public int EventHour { get; set; }    public int EventMinute { get; set; }    public string DisplayTitle { get; set; }}

在這兩個類中,CalendarEvent的Date將被拆分為CalendarEventForm的日期、時、分三個欄位,Title也將對應DisplayTitle欄位,那麼相應的Profile定義如下:

public class CalendarEventProfile : Profile{    protected override void Configure()    {        CreateMap<Entity.CalendarEvent, Entity.CalendarEventForm>()            .ForMember(dest => dest.EventDate, opt => opt.MapFrom(src => src.Date.Date))            .ForMember(dest => dest.EventHour, opt => opt.MapFrom(src => src.Date.Hour))            .ForMember(dest => dest.EventMinute, opt => opt.MapFrom(src => src.Date.Minute))            .ForMember(dest => dest.DisplayTitle, opt => opt.MapFrom(src => src.Title));    }}

測試代碼:

Entity.CalendarEvent calendarEvent = new Entity.CalendarEvent(){    Date = DateTime.Now,    Title = "Demo Event"};Entity.CalendarEventForm calendarEventForm = Mapper.Map<Entity.CalendarEventForm>(calendarEvent);ObjectDumper.Write(calendarEventForm);

測試結果:

驗證配置項(Configuration Validation)

AutoMapper提供了一種驗證機制,用來判斷Destination類中的所有屬性是否都被映射,如果存在未被映射的屬性,則拋出異常。

驗證的用法:

Mapper.AssertConfigurationIsValid();

例如:

public class Source{    public int SomeValue { get; set; }    public string AnotherValue { get; set; }}

Destination代碼:

public class Destination{    public int SomeValuefff { get; set; }}

測試:

Mapper.CreateMap<Entity.Source, Entity.Destination>();Mapper.AssertConfigurationIsValid();

運行程式將會出現AutoMapperConfigurationException異常:

這是因為SomeValuefff在Source類中沒有對應的欄位造成的。

解決這種異常的方法有:

指定映射欄位,例如:

Mapper.CreateMap<Entity.Source, Entity.Destination>()    .ForMember(dest => dest.SomeValuefff, opt =>    {        opt.MapFrom(src => src.SomeValue);    });

或者使用Ignore方法:

Mapper.CreateMap<Entity.Source, Entity.Destination>()    .ForMember(dest => dest.SomeValuefff, opt =>    {        opt.Ignore();    });

或者使用自訂解析器,自訂解析器在下面講到。

自訂解析器(Custom value resolvers)

AutoMapper允許我們自訂解析器來完成Source到Destination的值的轉換。例如:

public class Source{    public int Value1 { get; set; }    public int Value2 { get; set; }}public class Destination{    public int Total { get; set; }}

Total屬性在Source中不存在,如果現在建立映射規則,在映射的時候必然會拋出異常。這個時候我們就需要使用自訂解析器來完成映射。

自訂解析器需要實現 IValueResolver 介面,介面的定義如下:

public interface IValueResolver{    ResolutionResult Resolve(ResolutionResult source);}

我們來自訂一個Resolver:

public class CustomResolver : ValueResolver<Source, int>{    protected override int ResolveCore(Source source)    {        return source.Value1 + source.Value2;    }}

然後在映射規則中使用這個解析器:

public class SourceProfile : Profile{    protected override void Configure()    {        //Source->Destination        CreateMap<Source, Destination>()            .ForMember(dest => dest.Total, opt =>            {                opt.ResolveUsing<CustomResolver>();            });    }}

測試代碼:

Source src = new Source(){    Value1 = 1,    Value2 = 2};Destination dest = Mapper.Map<Destination>(src);ObjectDumper.Write(dest);

測試結果:

在使用自訂Resolver中,我們還可以指定Resolver的建構函式,例如:

//Source->DestinationCreateMap<Source, Destination>()    .ForMember(dest => dest.Total, opt =>    {        opt.ResolveUsing<CustomResolver>()            .ConstructedBy(() => 

new CustomResolver

());    });
自訂類型轉換器(Custom type converters)

AutoMapper通過ConvertUsing來使用自訂類型轉換器。ConvertUsing有三種用法:

void ConvertUsing(Func<TSource, TDestination> mappingFunction);void ConvertUsing(ITypeConverter<TSource, TDestination> converter);void ConvertUsing<TTypeConverter>() where TTypeConverter : ITypeConverter<TSource, TDestination>;

當我們有如下的Source類和Destination類:

public class Source{    public string Value1 { get; set; }}public class Destination{    public int Value1 { get; set; }}

我們可以使用如下配置:

public class SourceProfile : Profile{    protected override void Configure()    {        //string->int        CreateMap<string, int>()            .ConvertUsing(Convert.ToInt32);        //Source->Destination        CreateMap<Source, Destination>();    }}

在上面的配置中,我們首先建立了從string到int的類型轉換,這裡使用了系統內建的Convert.ToInt32轉換方法。

除了這種方法之外,我們還可以自訂類型轉換器:

public class CustomConverter : ITypeConverter<Source, Destination>{    public Destination Convert(ResolutionContext context)    {        Source src = context.SourceValue as Source;        Destination dest = new Destination();        dest.Value1 = System.Convert.ToInt32(src.Value1);        return dest;    }}

通過這個轉換器,我們可以繞過string到int的轉換,直接將Source類的對象轉換為Destination類的對象。

對應的配置如下:

public class SourceProfile : Profile{    protected override void Configure()    {        //Source->Destination        CreateMap<Source, Destination>()            .ConvertUsing<CustomConverter>();    }}

或者,我們也可以使用下面的配置:

public class SourceProfile : Profile{    protected override void Configure()    {        //Source->Destination        CustomConverter converter = new CustomConverter();        CreateMap<Source, Destination>()            .ConvertUsing(converter);    }}
空值替換(Null substitution)

空值替換允許我們將Source對象中的空值在轉換為Destination的值的時候,使用指定的值來替換空值。

public class Source{    public string Value { get; set; }}public class Destination{    public string Value { get; set; }}

配置代碼:

public class SourceProfile : Profile{    protected override void Configure()    {        //Source->Destination        CreateMap<Source, Destination>()            .ForMember(dest => dest.Value, opt =>            {                opt.NullSubstitute("原始值為NULL");            });    }}

測試代碼:

Source src = new Source();Destination dest = Mapper.Map<Destination>(src);ObjectDumper.Write(dest);

測試結果:

條件映射(Conditional mapping)

條件映射只當Source類中的屬性值滿足一定條件的時候才進行映射。例如:

public class Foo{    public int baz;}public class Bar{    public uint baz;}

對應的配置代碼如下:

Mapper.CreateMap<Foo, Bar>()    .ForMember(dest => dest.baz, opt =>    {        opt.Condition(src => (src.baz >= 0));    });


轉自:http://www.cnblogs.com/youring2/p/automapper.html

配置AutoMapper映射規則《轉》

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.