AutoMapper自動映射


十年河東,十年河西,莫欺少年窮。

學無止境,精益求精。

不扯犢子,直接進入正題:

AutoMapper自動映射常用於EF中,能很好的解決DTO和Model之間相互映射的問題。在未使用AutoMapper之前,我們回顧下傳統的對象相互映射的方法。

首先貼出本節要用到的DTO,學生表及系表,他們之間存在主外鍵關系!如下:

    public partial class Dept
    {
        public Dept()
        {
            this.Student = new HashSet<Student>();
        }
    
        public int Id { get; set; }
        public string deptNum { get; set; }
        public string deptName { get; set; }
    
        public virtual ICollection<Student> Student { get; set; }
    }

    public partial class Student
    {
        public int Id { get; set; }
        public string StuNum { get; set; }
        public string deptNum { get; set; }
        public string StuName { get; set; }
        public string StuSex { get; set; }
        public Nullable<System.DateTime> AddTime { get; set; }
    
        public virtual Dept Dept { get; set; }
    }
View Code

假設,現在要求將得到的學生對象轉化為Model

新建學生對象Model

    public class StudentModel
    {
        public int Id { get; set; }
        public string StuNum { get; set; }
        public string deptNum { get; set; }
        public string StuName { get; set; }
        public string StuSex { get; set; }
        public Nullable<System.DateTime> AddTime { get; set; }
    }
View Code

傳統方法如下:

        public ActionResult Index()
        {
            var profiler = MiniProfiler.Current;

            using (profiler.Step("查詢Student的數據"))
            {
                using (BingFaTestEntities context = new BingFaTestEntities())
                {
                    var SM = context.Student.Where(A => A.StuNum == "0813091000000").FirstOrDefault();
                    if (SM != null)
                    {
                        var StudetM = new StudentModel()
                        {
                            Id = SM.Id,
                            StuName = SM.StuNum,
                            StuNum = SM.StuNum,
                            StuSex = SM.StuSex,
                            deptNum = SM.deptNum,
                            AddTime = SM.AddTime
                        };
                    }
                }
                return View();
            }
        }
View Code

傳統方法實現相互映射存在一個弊端,如果數據表字段特別多,那么,試問你需要寫多少行代碼?

OK,AutoMapper閃亮登場,那么如果使用AutoMapper需要寫什么樣的代碼呢?

        public ActionResult Index()
        {
            var profiler = MiniProfiler.Current;

            using (profiler.Step("查詢Student的數據"))
            {
                using (BingFaTestEntities context = new BingFaTestEntities())
                {
                    var SM = context.Student.Where(A => A.StuNum == "0813091000000").FirstOrDefault();
                    if (SM != null)
                    {
                        StudentModel StudentM = Mapper.DynamicMap<StudentModel>(SM);
                    }
                }
                return View();
            }
        }
View Code

由上述代碼可知,其相互映射只需一行代碼搞定。這里需要注意,你定義的Model層個字段屬性要和DTO層字段屬性一致。

OK,那如果需要轉化一個泛型集合呢?

傳統方法如下:

        public ActionResult Index()
        {
            var profiler = MiniProfiler.Current;

            using (profiler.Step("查詢Student的數據"))
            {
                using (BingFaTestEntities context = new BingFaTestEntities())
                {
                    var SMList = context.Student.Where(A => A.StuName.Contains("")).ToList();
                    if (SMList != null&&SMList.Count>0)
                    {
                        foreach (var SM in SMList)
                        {
                            var StudetM = new StudentModel()
                            {
                                Id = SM.Id,
                                StuName = SM.StuNum,
                                StuNum = SM.StuNum,
                                StuSex = SM.StuSex,
                                deptNum = SM.deptNum,
                                AddTime = SM.AddTime
                            };
                        }
                    }
                }
                return View();
            }
        }
View Code

那么,AutoMapper是否可以做到呢?

當然,可以...

        public ActionResult Index()
        {
            var profiler = MiniProfiler.Current;

            using (profiler.Step("查詢Student的數據"))
            {
                using (BingFaTestEntities context = new BingFaTestEntities())
                {
                    var SMList = context.Student.Where(A => A.StuName.Contains("")).ToList();
                    if (SMList != null && SMList.Count > 0)
                    {
                        List<StudentModel> StudentM = Mapper.DynamicMap<List<StudentModel>>(SMList);
                    }
                }
                return View();
            }
        }
View Code

有上述代碼可知,是不是連Foreach都省了?

哈哈,OK,這些都是些基礎功能,咱們繼續深究。

如果需要映射導航屬性對應表中的字段怎么寫呢?

我們將StudentModel修改成如下:

如果要得到系名稱 deptName ,我們就要用到EF的懶加載。關於用EF懶加載時要注意的事項,大家可參考博客: EF性能優化-有人說EF性能低,我想說:EF確實不如ADO.NET,當然本節也會詳細說明。

首先用傳統方法實現如下:

        public ActionResult Index()
        {
            var profiler = MiniProfiler.Current;

            using (profiler.Step("查詢Student的數據"))
            {
                using (BingFaTestEntities context = new BingFaTestEntities())
                {
                    var SM = context.Student.Where(A => A.StuNum == "0813091000000").FirstOrDefault();
                    if (SM != null)
                    {
                        var StudetM = new StudentModel()
                        {
                            Id = SM.Id,
                            StuName = SM.StuNum,
                            StuNum = SM.StuNum,
                            StuSex = SM.StuSex,
                            deptNum = SM.deptNum,
                            AddTime = SM.AddTime,
                            deptName=SM.Dept.deptName
                        };
                    }
                }
                return View();
            }
        }
View Code

傳統方法變化不大,那么,用AutoMapper怎么實現呢?

        public ActionResult Index()
        {
            var profiler = MiniProfiler.Current;

            using (profiler.Step("查詢Student的數據"))
            {
                using (BingFaTestEntities context = new BingFaTestEntities())
                {
                    var SM = context.Student.Where(A => A.StuNum == "0813091000000").FirstOrDefault();
                    AutoMapper.Mapper.CreateMap<Student, StudentModel>().ForMember(dest => dest.deptName, opts => opts.MapFrom(src => src.Dept.deptName));
                   var model = AutoMapper.Mapper.Map<StudentModel>(SM);
                }
                return View();
            }
        }
View Code

由上述方法可知,使用AutoMapper方法進行映射,需要指定目標字段dest.deptName 以及 源字段 src.Dept.deptName,關於AutoMapper的詳細用法及說明大家可參考:【來龍去脈系列】AutoMapper一款自動映射框架

在這里,我要告誡大家關於使用懶加載的注意事項,如果你不注意,那么你寫的代碼效率有可能將會非常低。

如上述兩種方法,我們來監控下生成的SQL語句:(關於是如果監控生成的SQL語句,大家可參考我的博客:MiniProfiler工具介紹(監控EF生成的SQL語句)--EF,迷你監控器,哈哈哈

生成了2條SQL語句:

OK,僅僅生成兩條SQL語句還可以接受,但是如果你的項目數據表關系比較復雜,有很多導航屬性時,就會生成很多SQL語句,會產生極大的性能問題。

那么關於懶加載的問題怎么解決呢?還好,EF中有Include,在使用Include時需要引入using System.Data.Entity;

將上邊的程序修改成如下:

        public ActionResult Index()
        {
            var profiler = MiniProfiler.Current;

            using (profiler.Step("查詢Student的數據"))
            {
                using (BingFaTestEntities context = new BingFaTestEntities())
                {
                    var SMList = context.Student.Include(A=>A.Dept).Where(A => A.StuName.Contains("")).ToList();
                    AutoMapper.Mapper.CreateMap<Student, StudentModel>()
                        .ForMember(dest => dest.deptName, opts => opts.MapFrom(src => src.Dept.deptName));
                    var modelList = AutoMapper.Mapper.Map<List<StudentModel>>(SMList);
                }
                return View();
            }
        }
View Code

使用Include,其實相當於聲明棄用懶加載,這里使用顯示加載!

OK,關於使用AutoMapper應用懶加載的方法講完了。正如上述所說:AutoMapper是將DTO映射成Model,如果反過來映射是否可行呢?

還好,AutoMapper提供了.ReverseMap();方法,將Model映射成DTO,如下:

        public ActionResult Index()
        {
            var profiler = MiniProfiler.Current;

            using (profiler.Step("查詢Student的數據"))
            {
                using (BingFaTestEntities context = new BingFaTestEntities())
                {
                    StudentModel M = new StudentModel()
                    {
                        StuName = "陳星辰",
                        AddTime = DateTime.Now,
                        deptNum = "0813092",
                        StuNum = "081309201",
                        StuSex = ""
                    };
                    Student Sm = new Student();
                    AutoMapper.Mapper.CreateMap<StudentModel, Student>().ReverseMap();
                    Sm = AutoMapper.Mapper.Map<Student>(M);
                    context.Student.Add(Sm);
                    context.SaveChanges();
                }
                return View();
            }
        }
View Code

OK。截止到這里,關於AutoMapper的基礎用法也就講完了,本人能力有限,如有未提及之處,請大家多多指點。希望大家喜歡!

@陳卧龍的博客


免責聲明!

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



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