• 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的基础用法也就讲完了,本人能力有限,如有未提及之处,请大家多多指点。希望大家喜欢!

    @陈卧龙的博客

  • 相关阅读:
    简单算法题20200815
    求图的连通子图的个数并保存每个子图的节点python
    java遍历树,并得到每条根到叶子节点的路径
    volatile 对于n=n+1,无效
    java重载(overload)和重写(override)
    对象的上转型对象
    (阿里巴巴笔试题)直线上安装水塔,水塔到直线上其它点的距离之和最小
    选择排序、树形排序、堆排序的java代码实现
    linux里面那些奇奇怪怪但是还没有解决的问题
    Linux使用free命令buff/cache过高
  • 原文地址:https://www.cnblogs.com/chenwolong/p/AutoMapper.html
Copyright © 2020-2023  润新知