讓AutoMapper在你的專案裡飛一會兒

風靈使發表於2018-07-25

先說說DTO

DTO是個什麼東東?

DTO(Data Transfer Object)就是資料傳輸物件,說白了就是一個物件,只不過裡邊全是資料而已。

為什麼要用DTO?

1、DTO更注重資料,對領域物件進行合理封裝,從而不會將領域物件的行為過分暴露給表現層

2、DTO是面向UI的需求而設計的,而領域模型是面向業務而設計的。因此DTO更適合於和表現層的互動,通過DTO我們實現了表現層與領域Model之間的解耦,因此改動領域Model不會影響UI層

3、DTO說白了就是資料而已,不包含任何的業務邏輯,屬於瘦身型的物件,使用時可以根據不同的UI需求進行靈活的運用

AutoMapper

現在我們既然知道了使用DTO的好處,那麼我們肯定也想馬上使用它,但是這裡會牽扯一個問題:怎樣實現DTO和領域Model之間的轉換?

有兩個思路,我們要麼自己寫轉換程式碼,要麼使用工具。不過就應用而言,我還是覺得用工具比較簡單快捷,那就使用工具吧。其實這樣的轉換工具很多,不過我還是決定使用AutoMapper,因為它足夠輕量級,而且也非常流行,國外的大牛們都使用它。使用AutoMapper可以很方便的實現DTO和領域Model之間的轉換,它是一個強大的Object-Object Mapping工具。

一、如何新增AutoMapper到專案中?

在vs中使用開啟工具-庫程式包管理器-程式包管理控制平臺,輸入“Install-Package AutoMapper”命令,就可以把AutoMapper新增到專案中了~

二、吃點栗子

栗子1(兩個型別之間的對映)

Mapper.CreateMap<AddressDto, Address>();
             AddressDto dto = new AddressDto
              {
                  Country = "China",
                  City = "ShangHai",
                  Street = "JinZhong Street"
              };
Address address = Mapper.Map<AddressDto,Address>(Dto);

栗子2(兩個對映的物件有部分欄位名稱不一樣)

AddressDtoAddress的對映,AddressDto的欄位CountryName要對應Address的欄位Country

Mapper.CreateMap<AddressDto, Address>(). ForMember(d => d.Country, opt => opt.MapFrom(s => s.CountryName));

栗子3(列表型別之間的對映)

源型別List<Address>,目標型別List<AddressDto>

AutoMapper.Mapper.CreateMap< Address, AddressDto >();
var addressDtoList = AutoMapper.Mapper.Map<List< Address >, List< AddressDto >>( addressList);

栗子4(對映在增改查中的應用)

public class ProductBll
{
        Public IProductRepository productRepository{ set; get; }
        public ProductDTO CreateProduct(ProductDTO productDTO)
        {
            Mapper.CreateMap<ProductDTO, Product>();
            Product product = Mapper.Map<ProductDTO, Product>(productDTO);
            productRepository.AddProduct(product);
            return productDTO;
        }

        public List<ProductDTO> GetProduct()
        {
            Mapper.CreateMap<Product, ProductDTO>();
            List<ProductDTO> arr = new List<ProductDTO>();
            productRepository.GetProduct().ForEach(i =>
            {
                arr.Add(Mapper.Map<Product, ProductDTO>(i));
            });
            return arr;
        }

         public ProductDTO ModifyProduct(ProductDTO productDTO)
        {
            Mapper.CreateMap<ProductDTO, Product>();
            Product product = Mapper.Map<ProductDTO, Product>(productDTO);
            productRepository.ModifyProduct(product);
            return productDTO;
        }
}

三、讓AutoMapper使用變得簡單

吃過上面的栗子,你覺得怎麼樣呢?如果想繼續吃,那就去檢視AutoMapper的具體API文件吧!倘若在專案中真正要用的時候,我覺得還是應該對AutoMapper的方法進行一些整理,最好能夠封裝一下,這裡我通過擴充套件方法的形式將其封裝為AutoMapperHelper,這樣以後使用AutoMapper就變的SO EASY了~

using System.Collections;
using System.Collections.Generic;
using System.Data;
using AutoMapper;
namespace Infrastructure.Utility
{
    /// <summary>
    /// AutoMapper擴充套件幫助類
    /// </summary>
    public static class AutoMapperHelper
    {
        /// <summary>
        ///  型別對映
        /// </summary>
        public static T MapTo<T>(this object obj)
        {
            if (obj == null) return default(T);
            Mapper.CreateMap(obj.GetType(), typeof(T));
            return Mapper.Map<T>(obj);
        }
        /// <summary>
        /// 集合列表型別對映
        /// </summary>
        public static List<TDestination> MapToList<TDestination>(this IEnumerable source)
        {
            foreach (var first in source)
            {
                var type = first.GetType();
                Mapper.CreateMap(type, typeof(TDestination));
                break;
            }
            return Mapper.Map<List<TDestination>>(source);
        }
        /// <summary>
        /// 集合列表型別對映
        /// </summary>
        public static List<TDestination> MapToList<TSource, TDestination>(this IEnumerable<TSource> source)
        {
            //IEnumerable<T> 型別需要建立元素的對映
            Mapper.CreateMap<TSource, TDestination>();
            return Mapper.Map<List<TDestination>>(source);
        }
        /// <summary>
        /// 型別對映
        /// </summary>
        public static TDestination MapTo<TSource, TDestination>(this TSource source, TDestination destination)
            where TSource : class
            where TDestination : class
        {
           if (source == null) return destination;
            Mapper.CreateMap<TSource, TDestination>();
            return Mapper.Map(source, destination);
        }
        /// <summary>
        /// DataReader對映
        /// </summary>
        public static IEnumerable<T> DataReaderMapTo<T>(this IDataReader reader)
        {
            Mapper.Reset();
            Mapper.CreateMap<IDataReader, IEnumerable<T>>();
            return Mapper.Map<IDataReader, IEnumerable<T>>(reader);
        }
    }
}

你可以像下面的栗子這樣使用:

//物件對映
ShipInfoModel  shipInfoModel =  ShipInfo.MapTo<ShipInfoModel>();
//列表對映
List<ShipInfoModel> shipInfoModellist = ShipInfoList.MapToList<ShipInfoModel>();

小結

在專案中多使用DTO實現表現層與領域Model的解耦,用AutoMapper來實現DTO與領域Model的相互轉換,讓AutoMapper在你的專案裡飛一會兒

相關文章