網頁

2014年3月4日 星期二

AutoMapper - Complex Type 使用 Custom value resolvers 設定屬性轉換

在上一篇文章「AutoMapper - Complex Type 的資料對映」裡說明了幾種對於 Complex Type 的資料對映方式,其實還有一種方式,AutoMapper 提供了一種「Custom value resolvers(自定義值解析器)」,讓我們可以另外定義資料解析以及轉換的方式,以彈性的方式進行目標類別物件的資料對映。

這篇文章將會以前篇文章的程式來做示範。

 


下面是前一篇文章裡的程式,其中針對 ComplexModel 類別裡的 OrderModel 屬性有做資料對映的設定,

image

我必須說這程式的作法並不是很好,雖然我們在取得 Customer 資料時有特別過濾了是否有訂單資料的條件,但是這樣的做法式很有針對性的,是因為為了要讓程式看起來合理且不會發生錯誤,另外在設定資料對映的地方也是一樣,因為已經知道在取得資料時就已經會做一層過濾,所以不怕會有例外(Exception)的發生,所以就直接去取出第一筆訂單資料的值來做對映。

另外就是在做資料對映設定的部份,將全部的資料對映做一次性的設定,這樣的作法看起來好像結構比較完整,但是遇到比較特殊的對映設定時就會變得複雜,而且如果同樣的資料對映設定在其他的 Complex Type 也有的話,那是否就表示在其他地方又要重複的出現一樣的程式呢?

 

AutoMapper Wiki  - Custom value resolvers

在上面說明「Custom value resolvers」的連結裡可以看到,我們可以建立自定義 ValueResolver 類別,然後在 ResolveCore 方法裡進行資料對映的處理,而原本的 Mapper.CreateMap 設定裡只需使用 ResolveUsing 指定的 ValueResolver 類別與要進行對映轉換的原始資料就可以,而且建立的 ValueResolver 類別也可以在其他的資料對映設定重複使用。

首先建立 Customer ValueResolver 類別,要繼承「ValueResolver<TSource, TDestination>」類別,並且覆寫 ResolveCore 方法,在 ResolveCore 方法裡做資料對映的處理,

image

而原本 Mapper.CreateMap 設定裡,對於目標類別 ComplexModel 的 OrderModel 屬性的對映設定就是使用 ResolveUsing 並且指定使用 OrderModelResolver 類別,最後記得指定要進行資料對映的原始資料,

image

執行結果

image

 

接著我們可以將資料對映的設定從 Controller 裡抽離出來,使用之前文章「AutoMapper 的設定 (Configuration)」的內容,將設定放到 AutoMapperConfig.cs 內容,讓 Controller 與資料對映設定的程式不要混雜在一起而有所區隔。

AutoMapperConfig.cs

public class AutoMapperConfig
{
    public static void Configure()
    {
        Mapper.Initialize(x =>
        {
            x.AddProfile<ComplexModelProfile>();
        });
    }
 
    public class ComplexModelProfile : Profile
    {
        public override string ProfileName
        {
            get
            {
                return "ComplexModelProfile";
            }
        }
 
        protected override void Configure()
        {
            Mapper.CreateMap<Customer, ComplexModel>()
                  .ForMember(d => d.CustomerID, o => o.MapFrom(s => s.CustomerID))
                  .ForMember(d => d.Customer, o => o.MapFrom(s => s))
                  .ForMember(
                      d => d.OrderModel,
                      o => o.ResolveUsing<OrderModelResolver>()
                            .FromMember(s => s.Orders));
        }
 
        public class OrderModelResolver
            : ValueResolver<ICollection<Order>, OrderModel>
        {
            protected override OrderModel ResolveCore(ICollection<Order> source)
            {
                if (!source.Any())
                {
                    return null;
                }
                var order = source.OrderBy(x => x.OrderID).FirstOrDefault();
                var dest = new OrderModel()
                {
                    OrderID = order.OrderID,
                    OrderDate = order.OrderDate
                };
                return dest;
            }
        }
    }
}

記得要在 Global.asax 的 Application_Start() 方法裡加入 AutoMapperConfig.Configure();

image

最後原本 Contoller 裡的程式因為將資料對映設定的內容放到 AutoMapperConfig.cs 內,所以程式就只會剩下取得資料以及資料對映的部份,最後的執行結果仍然一樣,

image

可以跟之前的程式做個比對,

image

 

善用 Custom Value Resolver 讓複雜的資料對映設定另外處理,此外也可以在不同的資料對映設定裡重複使用,並且將程式流程內的程式抽離出來,讓各自的程式有所區隔以及責任區分,如此一來程式就會比較好維護。

 

以上

沒有留言:

張貼留言