AutoMapper自动映射

简介: 十年河东,十年河西,莫欺少年穷。学无止境,精益求精。不扯犊子,直接进入正题:AutoMapper自动映射常用于EF中,能很好的解决DTO和Model之间相互映射的问题。在未使用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的基础用法也就讲完了,本人能力有限,如有未提及之处,请大家多多指点。希望大家喜欢!

@陈卧龙的博客

目录
打赏
0
0
0
0
4
分享
相关文章
2021-08-05mapper代理,几种pojo输入输出,pojo扩展通过扩展继承,映射主键普通属性映射,动态SQL,逆向工程
2021-08-05mapper代理,几种pojo输入输出,pojo扩展通过扩展继承,映射主键普通属性映射,动态SQL,逆向工程
76 0
Hibernate框架【五】——基本映射——多对多映射
Hibernate框架【五】——基本映射——多对多映射
223 0
Hibernate框架【三】——基本映射——一对一映射
Hibernate框架【三】——基本映射——一对一映射
102 0
直接取配置文件对应数据映射到对象中,可在代码中直接使用
直接取配置文件对应数据映射到对象中,可在代码中直接使用
实体类的属性映射怎么可以少了它?(一)
我们都知道,随着一个工程的越来越成熟,模块划分会越来越细,其中实体类一般存于 domain 之中,但 domain 工程最好不要被其他工程依赖,所以其他工程想获取实体类数据时就需要在各自工程写 model,自定义 model 可以根据自身业务需要映射相应的实体属性。这样一来,这个映射工程貌似并不简单了。阿粉差点就犯难了……
实体类的属性映射怎么可以少了它?(三)
我们都知道,随着一个工程的越来越成熟,模块划分会越来越细,其中实体类一般存于 domain 之中,但 domain 工程最好不要被其他工程依赖,所以其他工程想获取实体类数据时就需要在各自工程写 model,自定义 model 可以根据自身业务需要映射相应的实体属性。这样一来,这个映射工程貌似并不简单了。阿粉差点就犯难了……
实体类的属性映射怎么可以少了它?(三)
实体类的属性映射怎么可以少了它?(二)
我们都知道,随着一个工程的越来越成熟,模块划分会越来越细,其中实体类一般存于 domain 之中,但 domain 工程最好不要被其他工程依赖,所以其他工程想获取实体类数据时就需要在各自工程写 model,自定义 model 可以根据自身业务需要映射相应的实体属性。这样一来,这个映射工程貌似并不简单了。阿粉差点就犯难了……
实体类的属性映射怎么可以少了它?(二)
实体类的属性映射怎么可以少了它?(四)
我们都知道,随着一个工程的越来越成熟,模块划分会越来越细,其中实体类一般存于 domain 之中,但 domain 工程最好不要被其他工程依赖,所以其他工程想获取实体类数据时就需要在各自工程写 model,自定义 model 可以根据自身业务需要映射相应的实体属性。这样一来,这个映射工程貌似并不简单了。阿粉差点就犯难了……
实体类的属性映射怎么可以少了它?(四)
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等