查看: 1360|回复: 0

[ASP.NET教程] C#使用AutoMapper6.2.2.0进行对象映射

发表于 2018-4-25 08:00:02
先说说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直接定义三个类:

      

  1. public class Student
  2. {
  3. public string Name { get; set; }
  4. public int Sex { get; set; }
  5. public string Age { get; set; }
  6. public DateTime Birth { get; set; }
  7. }
  8. public class Dto_Student
  9. {
  10. public string n { get; set; }
  11. public string s { get; set; }
  12. public int a { get; set; }
  13. public string b { get; set; }
  14. }
  15. public class V_Student
  16. {
  17. public string Name { get; set; }
  18. public int Sex { get; set; }
  19. public string Age { get; set; }
  20. public DateTime Birth { get; set; }
  21. }
复制代码

  (2)一个简单的映射,由于Student和V_Student类字段名称一样,类型相同,所以,映射可以这么写

  

  1. //一个简单的映射
  2. AutoMapper.Mapper.Initialize(map => map.CreateMap<Student, V_Student>());
  3. var stu = AutoMapper.Mapper.Map<Student>(new V_Student
  4. {
  5. Name = "myname",
  6. Sex = 1,
  7. Age = "24",
  8. Birth = DateTime.Now
  9. });
  10. var vstu = AutoMapper.Mapper.Map<V_Student>(new Student
  11. {
  12. Name = "myname",
  13. Sex = 1,
  14. Age = "24",
  15. Birth = DateTime.Now
  16. });
复制代码

  (3)那么,不同字段名称,甚至不同类型的两个类如何映射呢,那就要手动的映射相应字段了:

  1. //属性不同名,属性类型不同映射
  2. AutoMapper.Mapper.Initialize(map => map.CreateMap<Student, Dto_Student>()
  3. .ForMember(d => d.n, opt =>
  4. {
  5. opt.MapFrom(s => s.Name);
  6. })
  7. .ForMember(d => d.s, opt =>
  8. {
  9. opt.MapFrom(s => s.Sex == 1 ? "男" : "女");
  10. })
  11. .ForMember(d => d.a, opt =>
  12. {
  13. opt.MapFrom(s => Convert.ToInt32(s.Age));
  14. })
  15. .ForMember(d => d.b, opt =>
  16. {
  17. opt.MapFrom(s => s.Birth.ToString("yyyy-MM-dd"));
  18. })
  19. );
  20. var dto_stu = AutoMapper.Mapper.Map<Dto_Student>(new Student
  21. {
  22. Name = "myname",
  23. Sex = 1,
  24. Age = "24",
  25. Birth = DateTime.Now
  26. });
  27. var stu = AutoMapper.Mapper.Map<Student>(new Dto_Student
  28. {
  29. n = "myname",
  30. s = "男",
  31. a = 24,
  32. b = DateTime.Now.ToString("yyyy-MM-dd")
  33. });
复制代码

  这边一运行,发现报错了,为什么呢,原来是因为,由于映射字段类型不同,无法反向映射,那么,如何再添加一个映射呢,这时候就需要用到Profile这个类,我们需要继承这个类,并在里面写下映射配置,具体如下:

新建Dto_StudentProfile类和StudentProfile类:

  1. public class Dto_StudentProfile:Profile
  2. {
  3. public Dto_StudentProfile()
  4. {
  5. base.CreateMap<Dto_Student, Student>()
  6. .ForMember(s => s.Name, opt =>
  7. {
  8. opt.MapFrom(stu => stu.n);
  9. })
  10. .ForMember(s => s.Sex, opt =>
  11. {
  12. opt.MapFrom(stu => stu.s.Equals("男")?1:0);
  13. })
  14. .ForMember(s => s.Age, opt =>
  15. {
  16. opt.MapFrom(stu => stu.a.ToString());
  17. })
  18. .ForMember(s => s.Birth, opt =>
  19. {
  20. opt.MapFrom(stu =>DateTime.Parse( stu.b+" 00:00:00"));
  21. });
  22. }
  23. }
  24. public class StudentProfile:Profile
  25. {
  26. public StudentProfile()
  27. {
  28. base.CreateMap<Student, Dto_Student>()
  29. .ForMember(d => d.n, opt =>
  30. {
  31. opt.MapFrom(stu => stu.Name);
  32. })
  33. .ForMember(d => d.s, opt =>
  34. {
  35. opt.MapFrom(stu => stu.Sex == 1 ? "男" : "女");
  36. })
  37. .ForMember(d => d.a, opt =>
  38. {
  39. opt.MapFrom(stu => Convert.ToInt32(stu.Age));
  40. })
  41. .ForMember(d => d.b, opt =>
  42. {
  43. opt.MapFrom(stu => stu.Birth.ToString("yyyy-MM-dd"));
  44. });
  45. }
  46. }
复制代码

  那么,我们如何使用两个配置呢?

  1. //配置映射
  2. AutoMapper.Mapper.Initialize(map => map.AddProfiles(new[] {
  3. typeof(Dto_StudentProfile),
  4. typeof(StudentProfile)
  5. }));
  6. var dto_stu = AutoMapper.Mapper.Map<Dto_Student>(new Student
  7. {
  8. Name = "myname",
  9. Sex = 1,
  10. Age = "24",
  11. Birth = DateTime.Now
  12. });
  13. var stu = AutoMapper.Mapper.Map<Student>(new Dto_Student
  14. {
  15. n = "myname",
  16. s = "男",
  17. a = 24,
  18. b = DateTime.Now.ToString("yyyy-MM-dd")
  19. });
复制代码

  这样,我们就完成了两个不同字段名称,不同类型的映射

(4)映射List

  如何进行实体列表的映射呢,其实,配置上并没有任何不同,只需要在使用上,换成list就可以了:

  1. List<Student> estu = new List<Student>();
  2. estu.Add(new Student
  3. {
  4. Name = "myname",
  5. Sex = 1,
  6. Age = "24",
  7. Birth = DateTime.Now
  8. });
  9. estu.Add(new Student
  10. {
  11. Name = "myname",
  12. Sex = 1,
  13. Age = "24",
  14. Birth = DateTime.Now
  15. });
  16. 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操作类:

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Text;
  5. namespace AutoMapperTest
  6. {
  7. public static class AutoMapperHelper
  8. {
  9. public static T MapTo<T>(this object obj)
  10. {
  11. if (obj == null) return default(T);
  12. return AutoMapper.Mapper.Map<T>(obj);
  13. }
  14. public static List<TDestination> MapToList<TDestination>(this object source)
  15. {
  16. return AutoMapper.Mapper.Map<List<TDestination>>(source);
  17. }
  18. }
  19. }
复制代码

  这样,你就可以这么使用:

  1. List<Student> estu = new List<Student>();
  2. estu.Add(new Student
  3. {
  4. Name = "myname",
  5. Sex = 1,
  6. Age = "24",
  7. Birth = DateTime.Now
  8. });
  9. estu.Add(new Student
  10. {
  11. Name = "myname",
  12. Sex = 1,
  13. Age = "24",
  14. Birth = DateTime.Now
  15. });
  16. var slist = estu.MapToList<Dto_Student>();
复制代码

  非list的实体映射也是一样的,这里不再多说,如果有什么疑问,欢迎提出来,共同讨论进步,感谢你的阅读



回复

使用道具 举报