前言

上一篇介紹了三層式架構,有些人可能會有疑問,三層各有自己的 Model ,那要怎麼將各個 Model 轉換呢?

難道是每一次轉換都需要跑一次迴圈,那也太麻煩了;這時就要介紹好用的工具 Automapper了。

本文

基本用法

首先到 Nuget 安裝 Automapper。

安裝好後我們建立兩個測試用的 Model

        private class Model1
        {
            public string Name { get; set; }
            public int Id { get; set; }
        }

        private class Model2
        {
            public string Name { get; set; }
            public int Id { get; set; }
        }

使用 Automapper 對應 Model1 到 Model2。

           var testModel = new Model1
            {
                Name = "ALLEN",
                Id = 1
            };

            var config = new MapperConfiguration(cfg => cfg.CreateMap<Model1, Model2>());
                                                                 //從左邊Model對應到右邊
            var mapper = config.CreateMapper();
            var model2 = mapper.Map<Model2>(testModel);

            Console.WriteLine($"Model2 Id:{model2.Id}");
            Console.WriteLine($"Model2 Name:{model2.Name}");

結果:

如此一來就可以很輕鬆的對應 Model 了。

偷懶小技巧:如果一時分不清是哪個 Model 要對應到哪個 Model,那可以加上 ReverseMap 反轉雙向對應。

var config = new MapperConfiguration(cfg => 
cfg.CreateMap<Model1, Model2>().ReverseMap());

客製化對應

我們上一篇講到的三層式架構,有提到每一層分工的時候會建立自己的 Model 有的時候可能各層間 Model 命名方式不同、或是需要對 Model 進行特殊處理,那就可以用以下方法來處理對應。

一樣先建立兩個測試用 Model

        private class Model1
        {
            public string Name { get; set; }
            public int Id { get; set; }
        }

        private class Model2
        {
            public string Name { get; set; }
            public int UserId { get; set; }
        }

建立對應:

          var testModel = new Model1
            {
                Name = "ALLEN",
                Id = 1
            };

            var config = new MapperConfiguration(cfg => 
            cfg.CreateMap<Model1, Model2>()
            .ForMember(x => x.UserId, y => y.MapFrom(z => z.Id)));
            
            var mapper = config.CreateMapper();
            var model2 = mapper.Map<Model2>(testModel);

            Console.WriteLine($"Model2 Id:{model2.UserId}");
            Console.WriteLine($"Model2 Name:{model2.Name}");

結果:

進行特殊處理方式

首先在 Model2 多加一個 string

        private class Model2
        {
            public string Name { get; set; }
            public int UserId { get; set; }
            public string User { get; set; }
        }
           var testModel = new Model1
            {
                Name = "ALLEN",
                Id = 1
            };

            var config = new MapperConfiguration(cfg =>
            cfg.CreateMap<Model1, Model2>()
            .ForMember(x => x.UserId, y => y.MapFrom(z => z.Id))
            .ForMember(x => x.User, y => y.MapFrom(z => $"{z.Id}、{z.Name}")));
            
            var mapper = config.CreateMapper();
            var model2 = mapper.Map<Model2>(testModel);

            Console.WriteLine($"Model2 UserId:{model2.UserId}");
            Console.WriteLine($"Model2 Name:{model2.Name}");
            Console.WriteLine($"Model2 User:{model2.User}");

結果:

這邊做點小提醒,因為可以透過此種方式很方便的對 Model 對應出來的資料動手腳,那麼下一個人接手的時候就有機會找不到資料是在哪邊被動過了,所以使用 ForMember 做特殊對應的話建議還是要特別註明。

忽略對應

除了可以做到小處理 Automapper 也支援忽略對應,可以用此種方式達到。

       private static void Main(string[] args)
        {
            var testModel = new Model1
            {
                Name = "ALLEN",
                Id = 1
            };

            var config = new MapperConfiguration(cfg =>
            cfg.CreateMap<Model1, Model2>()
            .ForMember(x => x.UserId, y => y.Ignore())   //忽略此項
            .ForMember(x => x.User, y => y.MapFrom(z => $"{z.Id}、{z.Name}")));
            
            var mapper = config.CreateMapper();
            var model2 = mapper.Map<Model2>(testModel);

            Console.WriteLine($"Model2 UserId:{model2.UserId}");
            Console.WriteLine($"Model2 Name:{model2.Name}");
            Console.WriteLine($"Model2 User:{model2.User}");
        }

結果:

集中管理

上面示範用法都是在個別區塊中使用,這樣不方便管理,我們可以建立一個 profile 檔案繼承 Automapper 的 profile 來集中管理這些 mapping。

首先 dotnet core 要先安裝 AutoMapper.Extensions.Microsoft.DependencyInjection。

接下來建立一個 profile 檔案繼承 Profile。

    public class ControllerProfile : Profile
    {
        public ControllerProfile()
        {
            CreateMap<Model1, Model2>();
            //CreateMap<>();  接著建立其他mapping
        }
    }

再到 startup 內 ConfigureServices 註冊 Automapper。

services.AddAutoMapper(typeof(ControllerProfile));
            //將剛剛建好的ControllerProfile加入註冊

接下來我們可以透過注入的方式使用 mapping。

        private IMapper _mapper;

        public WeatherForecastController(
            IMapper mapper)
        {
            this._mapper = mapper;
        }

測試一下

        public Model2 Get()
        {
            var testModel = new Model1
            {
                Name = "ALLEN",
                Id = 1
            };

            var model2 = this._mapper.Map<Model2>(testModel);

            return model2;
        }

如此一來就可以透過簡單的方式轉換各個 Model,提供這方便的套件供大家參考使用。

參考連結