C#使用AutoMapper6.2.2.0進行對象映射


先說說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在你的項目里飛一會兒

AutoMapper6.2.2.0

AutoMapper6.2.2.0與之前的版本有些不同,那么究竟有什么不同,我們一起來實踐一下:

1.首先,使用AutoMapper6.2.2.0需要在你的項目中引用NuGet包,右鍵依賴項,管理NuGet程序包,然后選擇瀏覽,搜索AutoMapper,安裝,你就可以在項目中使用啦,你也可以在vs中使用打開工具-庫程序包管理器-程序包管理控制平台,輸入“Install-Package AutoMapper”命令,就可以把AutoMapper添加到項目中了~

2.讓我們開始使用

  (1)一個簡單的映射

      首先,創建一個C#控制台應用程序,為了方便,我們在Program直接定義三個類:

      

public class Student
    {
        public string Name { get; set; }
        public int Sex { get; set; }
        public string Age { get; set; }
        public DateTime Birth { get; set; }
    }

    public class Dto_Student
    {
        public string n { get; set; }
        public string s { get; set; }
        public int a { get; set; }
        public string b { get; set; }
    }

    public class V_Student
    {
        public string Name { get; set; }
        public int Sex { get; set; }
        public string Age { get; set; }
        public DateTime Birth { get; set; }
    }

  (2)一個簡單的映射,由於Student和V_Student類字段名稱一樣,類型相同,所以,映射可以這么寫

  

//一個簡單的映射
            AutoMapper.Mapper.Initialize(map => map.CreateMap<Student, V_Student>());
            var stu = AutoMapper.Mapper.Map<Student>(new V_Student
            {
                Name = "myname",
                Sex = 1,
                Age = "24",
                Birth = DateTime.Now
            });

            var vstu = AutoMapper.Mapper.Map<V_Student>(new Student
            {
                Name = "myname",
                Sex = 1,
                Age = "24",
                Birth = DateTime.Now
            });

  (3)那么,不同字段名稱,甚至不同類型的兩個類如何映射呢,那就要手動的映射相應字段了:

//屬性不同名,屬性類型不同映射
            AutoMapper.Mapper.Initialize(map => map.CreateMap<Student, Dto_Student>()
                .ForMember(d => d.n, opt =>
                {
                    opt.MapFrom(s => s.Name);
                })
                .ForMember(d => d.s, opt =>
                {
                    opt.MapFrom(s => s.Sex == 1 ? "男" : "女");
                })
                .ForMember(d => d.a, opt =>
                {
                    opt.MapFrom(s => Convert.ToInt32(s.Age));
                })
                .ForMember(d => d.b, opt =>
                {
                    opt.MapFrom(s => s.Birth.ToString("yyyy-MM-dd"));
                })
            );

            var dto_stu = AutoMapper.Mapper.Map<Dto_Student>(new Student
            {
                Name = "myname",
                Sex = 1,
                Age = "24",
                Birth = DateTime.Now
            });

            var stu = AutoMapper.Mapper.Map<Student>(new Dto_Student
            {
                n = "myname",
                s = "男",
                a = 24,
                b = DateTime.Now.ToString("yyyy-MM-dd")
            });

  這邊一運行,發現報錯了,為什么呢,原來是因為,由於映射字段類型不同,無法反向映射,那么,如何再添加一個映射呢,這時候就需要用到Profile這個類,我們需要繼承這個類,並在里面寫下映射配置,具體如下:

新建Dto_StudentProfile類和StudentProfile類:

public class Dto_StudentProfile:Profile
    {
        public Dto_StudentProfile()
        {
            base.CreateMap<Dto_Student, Student>()
                .ForMember(s => s.Name, opt =>
                {
                    opt.MapFrom(stu => stu.n);
                })
                .ForMember(s => s.Sex, opt =>
                {
                    opt.MapFrom(stu => stu.s.Equals("男")?1:0);
                })
                .ForMember(s => s.Age, opt =>
                {
                    opt.MapFrom(stu => stu.a.ToString());
                })
                .ForMember(s => s.Birth, opt =>
                {
                    opt.MapFrom(stu =>DateTime.Parse( stu.b+" 00:00:00"));
                });
        }
    }

public class StudentProfile:Profile
    {
        public StudentProfile()
        {
            base.CreateMap<Student, Dto_Student>()
                .ForMember(d => d.n, opt =>
                {
                    opt.MapFrom(stu => stu.Name);
                })
                .ForMember(d => d.s, opt =>
                {
                    opt.MapFrom(stu => stu.Sex == 1 ? "男" : "女");
                })
                .ForMember(d => d.a, opt =>
                {
                    opt.MapFrom(stu => Convert.ToInt32(stu.Age));
                })
                .ForMember(d => d.b, opt =>
                {
                    opt.MapFrom(stu => stu.Birth.ToString("yyyy-MM-dd"));
                });
        }
    }

  那么,我們如何使用兩個配置呢?

//配置映射
AutoMapper.Mapper.Initialize(map => map.AddProfiles(new[] {
    typeof(Dto_StudentProfile),
    typeof(StudentProfile)
}));
var dto_stu = AutoMapper.Mapper.Map<Dto_Student>(new Student
            {
                Name = "myname",
                Sex = 1,
                Age = "24",
                Birth = DateTime.Now
            });

            var stu = AutoMapper.Mapper.Map<Student>(new Dto_Student
            {
                n = "myname",
                s = "男",
                a = 24,
                b = DateTime.Now.ToString("yyyy-MM-dd")
            });

  這樣,我們就完成了兩個不同字段名稱,不同類型的映射

(4)映射List<T>

  如何進行實體列表的映射呢,其實,配置上並沒有任何不同,只需要在使用上,換成list就可以了:

List<Student> estu = new List<Student>();
            estu.Add(new Student
            {
                Name = "myname",
                Sex = 1,
                Age = "24",
                Birth = DateTime.Now
            });
            estu.Add(new Student
            {
                Name = "myname",
                Sex = 1,
                Age = "24",
                Birth = DateTime.Now
            });
            List<Dto_Student> slist = AutoMapper.Mapper.Map<List<Student>, List<Dto_Student>>(estu);

  (5)你可能覺得不太方便,那么,我們可以將AutoMapper的Initialize放到應用開始的時候運行

  Mvc項目,可以放到程序的Global中,如果是.NET Core 2.0的MVC項目,可以放到StartUp中運行:

這邊直接摘了前人的方法,有興趣可以看一下https://www.cnblogs.com/lvlinlv/p/7344916.html

  (6)那么,你可以使用拓展的方法進行映射,這里定義一個AutoMapperHelper操作類:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace AutoMapperTest
{
    public static class AutoMapperHelper
    {
        public static T MapTo<T>(this object obj)
        {
            if (obj == null) return default(T);
            return AutoMapper.Mapper.Map<T>(obj);
        }

        public static List<TDestination> MapToList<TDestination>(this object source)
        {
            return AutoMapper.Mapper.Map<List<TDestination>>(source);
        }
    }
}

  這樣,你就可以這么使用:

List<Student> estu = new List<Student>();
            estu.Add(new Student
            {
                Name = "myname",
                Sex = 1,
                Age = "24",
                Birth = DateTime.Now
            });
            estu.Add(new Student
            {
                Name = "myname",
                Sex = 1,
                Age = "24",
                Birth = DateTime.Now
            });
            var slist = estu.MapToList<Dto_Student>();

  非list的實體映射也是一樣的,這里不再多說,如果有什么疑問,歡迎提出來,共同討論進步,感謝你的閱讀

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM