Asp.NetCore之AutoMapper基礎篇

應用場景

       如今因爲先後端技術的分離,後端程序員在使用ORM框架開發後臺API接口的時候,每每會將數據庫的「數據模型」直接提供給前端。而大多數時候,可能這些數據並不可以知足前端展現的需求,有時候可能須要在「數據模型」的基礎上,加幾個字段或者改幾個字段展現名稱或者字段展現風格,以知足前端「視圖模型」的需求。遇到這種狀況,後端每每須要同時定義「數據模型」和「視圖模型」,並在二者之間作大量的字段賦值工做,若是「數據模型」和「視圖模型」差異不大的話,這無疑很耗費心力,並且容易出錯。前端

        咱們先來理解兩個概念「數據模型」和「視圖模型」:git

        「數據模型」:最簡單的一種「」數據模型「」你能夠把它當成是數據庫表對象模型(數據模型字段一一對應數據庫表結構,是數據庫表的一種表現形式),使用ORM的小夥伴應該都知道,經過ORM數據庫模型能夠直接映射到數據表結構,能夠直接操做數據庫。程序員

        「視圖模型」:經過這個名稱咱們很容易理解,視圖模型是前端展現頁面中所需元素的一個集合。github

        當咱們將「數據模型」轉換成「視圖模型」提供給前端的時候,務必會產生大量的模型字段賦值的工做,模型很大的時候是否是想死的心都有了。。。AutoMapper的出現正是解決了兩個模型之間枯燥無味的轉換工做,用戶只須要簡單設置一下轉換規則便可,避免了咱們每次都採用手工編寫代碼的方式進行轉換。數據庫

       本文項目源碼:https://github.com/chenxf1117/Asp.NetCore-AutoMapper後端

.NetCore快速上手

1.建立項目

 

添加數據庫「數據模型」:數組

    /// <summary>
    /// 訂單表
    /// </summary>
    public class Order
    {
        /// <summary>
        /// ID
        /// </summary>
        public int Id { get; set; }
        /// <summary>
        /// 訂單名稱
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 價格
        /// </summary>
        public decimal Price { get; set; }

        public DateTime CreateTime { get; set; }

        public int CustomId { get; set; }
}
    /// <summary>
    /// 訂單子表
    /// </summary>
    public class OrderItem
    {
        public int ItemId { get; set; }
        public int OrderId { get; set; }
        public decimal Price { get; set; }
        /// <summary>
        /// 建立時間
        /// </summary>
        public DateTime CreateTime { get; set; }
    }

 2.添加AutoMapper依賴包

第二個包是.NetCore依賴注入使用。app

3.項目中添加「視圖模型」

    /// <summary>
    /// 訂單映射模型
    /// </summary>
    public class OrderDTO
    {
        public int Id { get; set; }
        /// <summary>
        /// 訂單名稱
        /// </summary>
        public string OrderName { get; set; }
        public decimal Price { get; set; }
        public DateTime CreateTime { get; set; }
        public int CustomId { get; set; }
    }
    /// <summary>
    /// 訂單子表映射模型
    /// </summary>
    public class OrderItemDTO
    {
        public int ItemId { get; set; }
        public int OrderId { get; set; }
        public decimal Price { get; set; }
        /// <summary>
        /// 建立時間
        /// </summary>
        public string CreateTime { get; set; }
    }

 4.添加自定義AutoMapper映射文件(OrderMapperProfile)

 在.NetCore咱們須要建立一個本身的映射配置類,該配置類必須繼承AutoMapper的Profile抽象類,而後才能經過依賴注入AutoMapper的方式調用。框架

    /// <summary>
    /// 映射配置
    /// </summary>
    public class OrderMapperProfile : Profile
    {
        public OrderMapperProfile()
        {
            //字段名稱不一致 Name映射到OrderName
            CreateMap<Order, OrderDTO>().ForMember(dest => dest.OrderName, src => src.MapFrom(s => s.Name));
            //字段類型不一致 DateTime映射到String
            CreateMap<OrderItem, OrderItemDTO>().ForMember(dest => dest.CreateTime, src => src.ConvertUsing(new FormatConvert()));
        }
    }

    /// <summary>
    /// DateTime映射到String
    /// </summary>
    public class FormatConvert : IValueConverter<DateTime, string>
    {
        public string Convert(DateTime sourceMember, ResolutionContext context)
        {
            if (sourceMember == null)
                return DateTime.Now.ToString("yyyyMMddHHmmssfff");
            return sourceMember.ToString("yyyyMMddHHmmssfff");
        }
    }

 1)自定義映射文件需繼承AutoMapper抽象類「Profile」async

 2)調用方法CreateMap實現模型映射

public IMappingExpression<TSource, TDestination> CreateMap<TSource, TDestination>(MemberList memberList);
public IMappingExpression<TSource, TDestination> CreateMap<TSource, TDestination>();

 TSource表明「數據模型」,TDestination表明「視圖模型」,MemberList可選,默認0

    public enum MemberList
    {
        /// <summary>
        /// 檢查是否已映射全部目標成員
        /// </summary>
        Destination = 0,

        /// <summary>
        /// 檢查是否已映射全部源成員
        /// </summary>
        Source = 1,

        /// <summary>
        /// 既不檢查源成員也不檢查目標成員,跳過驗證
        /// </summary>
        None = 2
    }

例如:

CreateMap<Order, OrderDTO>();

3)調用ForMember自定義兩個模型之間映射規則。

     由於 AutoMapper 默認是經過匹配字段名稱和類型進行自動匹配,因此若是你進行轉換的兩個類的中的某些字段名稱不同,這裏咱們就須要進行手動的編寫轉換規則。

IMappingExpression<TSource, TDestination> ForMember<TMember>(Expression<Func<TDestination, TMember>> destinationMember, Action<IMemberConfigurationExpression<TSource, TDestination, TMember>> memberOptions);

     其中比較經常使用的:

      1.兩個映射模型屬性/字段名稱不一致。

//字段名稱不一致 源類型Name映射到目標類型OrderName
CreateMap<Order, OrderDTO>().ForMember(dest => dest.OrderName, src => src.MapFrom(s => s.Name));

      2.兩個映射模型屬性/字段數據類型或展示形式不一致。

//字段類型不一致 源類型DateTime映射到目標類型String字符串
CreateMap<OrderItem, OrderItemDTO>().ForMember(dest => dest.CreateTime, src => src.ConvertUsing(new FormatConvert()));

ConvertUsing()方法中需實現成員參數接口IValueConverter中的Convert方法,實現自定義轉換

void ConvertUsing<TSourceMember>(IValueConverter<TSourceMember, TMember> valueConverter);
    public interface IValueConverter<in TSourceMember, out TDestinationMember>
    {
        TDestinationMember Convert(TSourceMember sourceMember, ResolutionContext context);
    }

自定義實現接口Convert方法,實現DateTime轉string字符串:

    /// <summary>
    /// DateTime映射到String
    /// </summary>
    public class FormatConvert : IValueConverter<DateTime, string>
    {
        public string Convert(DateTime sourceMember, ResolutionContext context)
        {
            if (sourceMember == null)
                return DateTime.Now.ToString("yyyyMMddHHmmssfff");
            return sourceMember.ToString("yyyyMMddHHmmssfff");
        }
    }

5.配置好映射文件後,.NetCore中須要註冊咱們剛纔的自定義Profile

 //註冊AutoMapper
 //方式1  指定映射配置文件  多個可用數組表示
 services.AddAutoMapper(typeof(OrderMapperProfile));
 //方式2   註冊程序集下面全部映射文件
 services.AddAutoMapper(Assembly.Load("程序集dll名稱"))

6.最後咱們能夠經過注入AutoMapper的方式,在業務邏輯層使用咱們的自定義映射配置文件Profile

public class OrderService : IOrderService
    {
        private readonly IMapper mapper;
        /// <summary>
        /// 構造函數注入Mapper
        /// </summary>
        /// <param name="_dBContext"></param>
        /// <param name="_mapper"></param>
        public OrderService(IMapper _mapper)
        {
            mapper = _mapper;
        }
        /// <summary>
        /// 名稱不一致  映射
        /// </summary>
        /// <returns></returns>
        public async Task<List<OrderDTO>> Query()
        {
            //ORM獲取數據模型數據
            var orderList = await dBContext.DB.Queryable<Order>().ToListAsync();
            //DTO映射
            var orderDtoList = mapper.Map<List<OrderDTO>>(orderList);
            return await Task.FromResult(orderDtoList);
        }

        /// <summary>
        /// 數據類型/展示形式不一致 映射
        /// </summary>
        /// <returns></returns>
        public async Task<List<OrderItemDTO>> QueryItem()
        {
            var orderList = await dBContext.DB.Queryable<OrderItem>().ToListAsync();
            var orderDtoList = mapper.Map<List<OrderItemDTO>>(orderList);
            return await Task.FromResult(orderDtoList);
        }
    }

7.實現效果

 1)「數據模型」Order類型中的Name屬性值  映射到  「視圖模型」OrderDTO類型中的OrderName

 

  2)「數據模型」OrderItem類型中的CreateTime屬性DateTime數據類型  映射到  「視圖模型」OrderItemDTO類型中的CreateTime屬性string數據類型

 小結

      本篇文章主要簡單介紹下在Asp.NetCore項目中如何快速上手AutoMapper,整體來看想要上手仍是比較簡單,只要掌握好幾個常用的映射規則就能夠了。固然,AutoMapper爲咱們準備了各類自定規則的入口,有興趣的小夥伴能夠下載源碼,源碼中包含了不少測試用例,學習起來也比較容易理解。附上AutoMapper源碼地址:https://github.com/AutoMapper/AutoMapper

相關文章
相關標籤/搜索