ASP.NET Core 3.1系列(23)——使用AutoMapper实现实体之间的相互转换

32 篇文章 43 订阅

1、前言

在之前的博客中,我们通过EFCoreScaffold-DbContext命令一键生成数据库实体类。但在实际业务中,实体类并不能很好地应对所有情况。例如前端页面只需要展示某张表中部分字段的信息,这时如果直接将实体类集合返回给前端界面,就有可能造成数据的冗余和泄露问题。而在某些情况下,前端界面需要展示的字段信息可能并不包含在当前的实体类中。因此在实际业务中,可以考虑定义一系列的DTO实体类来解决上述问题,这也就涉及到实体类之间的相互转换问题。在ASP.NET Core中,一般推荐使用AutoMapper来实现实体转换操作,下面开始介绍它的用法。

2、低效的实体转换操作

这里通过控制台程序来说明,定义一个实体类Person,其中包含若干属性,代码如下:

namespace MapperApp
{
    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Gender { get; set; }
        public int Age { get; set; }
        public string Phone { get; set; }
        public string Email { get; set; }
    }
}

Person中包含一系列属性,但在实际业务中可能只需要显示NameGenderAge3个属性,这时可以考虑将它们提取出来单独建一个类PersonDto,代码如下所示:

namespace MapperApp
{
    public class PersonDto
    {
        public string Name { get; set; }
        public string Gender { get; set; }
        public int Age { get; set; }
    }
}

那么如何将Person转换为PersonDto呢?低效的做法就是手写转换过程,代码如下所示:

using System;
using System.Collections.Generic;

namespace MapperApp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            List<Person> pos = new List<Person>
            {
                new Person { Id = 1, Name = "张三", Gender = "男", Age = 30, Phone = "1111", Email = "1111@qq.com" },
                new Person { Id = 2, Name = "李四", Gender = "女", Age = 31, Phone = "2222", Email = "2222@qq.com" },
                new Person { Id = 3, Name = "王五", Gender = "男", Age = 32, Phone = "3333", Email = "3333@qq.com" }
            };

            // 转换为DTO
            List<PersonDto> dtos = new List<PersonDto>();
            foreach (Person po in pos)
            {
                dtos.Add(new PersonDto { Name = po.Name, Gender = po.Gender, Age = po.Age });
            }

            // 打印
            foreach (PersonDto dto in dtos)
            {
                Console.WriteLine(dto.Name + "," + dto.Gender + "," + dto.Age);
            }
            Console.ReadKey();
        }
    }
}

运行结果如下所示:

张三,男,30
李四,女,31
王五,男,32

虽然上述方法可以解决问题,但相信你也发现了:如果有多个方法都需要返回DTO对象,那么这种低效的转换代码就需要进行多次编写,因此上述方法并不是最优方法。

3、AutoMapper下的实体转换操作

现在来看看AutoMapper是如何处理转换问题的。在工程中使用NuGet引入如下组件:

AutoMapper

在这里插入图片描述

3.1、AutoMapper的基础操作

AutoMapper中主要使用MapperConfigurationIMapper来进行转换操作,前者负责定义转换规则,后者负责获取转换后的实体,代码如下:

using AutoMapper;
using System;
using System.Collections.Generic;

namespace MapperApp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 创建对象映射工具
            MapperConfiguration configuration = new MapperConfiguration(options =>
            {
                options.CreateMap<Person, PersonDto>().ForMember(dest => dest.Name, e => e.MapFrom(src => src.Name))
                                                      .ForMember(dest => dest.Gender, e => e.MapFrom(src => src.Gender))
                                                      .ForMember(dest => dest.Age, e => e.MapFrom(src => src.Age));
            });
            IMapper mapper = configuration.CreateMapper();

            // 原始数据
            List<Person> pos = new List<Person>
            {
                new Person { Id = 1, Name = "张三", Gender = "男", Age = 30, Phone = "1111", Email = "1111@qq.com" },
                new Person { Id = 2, Name = "李四", Gender = "女", Age = 31, Phone = "2222", Email = "2222@qq.com" },
                new Person { Id = 3, Name = "王五", Gender = "男", Age = 32, Phone = "3333", Email = "3333@qq.com" }
            };

            // 转换为DTO
            List<PersonDto> dtos = mapper.Map<List<PersonDto>>(pos);
            foreach (PersonDto dto in dtos)
            {
                Console.WriteLine(dto.Name + "," + dto.Gender + "," + dto.Age);
            }
            Console.ReadKey();
        }
    }
}

运行结果如下所示:

张三,男,30
李四,女,31
王五,男,32

在上面的代码中,我们只需要定义Person转换到PersonDto的规则即可,AutoMapper会解析该规则,实现PersonPersonDtoList<Person>List<PersonDto>的转换操作。其实上述规则写的有些繁琐,由于PersonPersonDto中的字段名称一致,因此也可以使用简易写法,代码如下:

using AutoMapper;
using System;
using System.Collections.Generic;

namespace MapperApp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 创建对象映射工具
            MapperConfiguration configuration = new MapperConfiguration(options =>
            {
                options.CreateMap<Person, PersonDto>();
            });
            IMapper mapper = configuration.CreateMapper();

            // 原始数据
            List<Person> pos = new List<Person>
            {
                new Person { Id = 1, Name = "张三", Gender = "男", Age = 30, Phone = "1111", Email = "1111@qq.com" },
                new Person { Id = 2, Name = "李四", Gender = "女", Age = 31, Phone = "2222", Email = "2222@qq.com" },
                new Person { Id = 3, Name = "王五", Gender = "男", Age = 32, Phone = "3333", Email = "3333@qq.com" }
            };

            // 转换为DTO
            List<PersonDto> dtos = mapper.Map<List<PersonDto>>(pos);
            foreach (PersonDto dto in dtos)
            {
                Console.WriteLine(dto.Name + "," + dto.Gender + "," + dto.Age);
            }
            Console.ReadKey();
        }
    }
}

运行结果如下所示:

张三,男,30
李四,女,31
王五,男,32

3.2、AutoMapper的双向映射

上面的代码定义了PersonPersonDto的转换规则,那么PersonDtoPerson的转换规则又该如何定义呢?我们当然可以手动编写这两者之间的转换规则,代码如下:

using AutoMapper;
using System;
using System.Collections.Generic;

namespace MapperApp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 创建对象映射工具
            MapperConfiguration configuration = new MapperConfiguration(options =>
            {
                // Person到PersonDto规则
                options.CreateMap<Person, PersonDto>().ForMember(dest => dest.Name, e => e.MapFrom(src => src.Name))
                                                      .ForMember(dest => dest.Gender, e => e.MapFrom(src => src.Gender))
                                                      .ForMember(dest => dest.Age, e => e.MapFrom(src => src.Age));

                // PersonDto到Person规则
                options.CreateMap<PersonDto, Person>().ForMember(dest => dest.Name, e => e.MapFrom(src => src.Name))
                                                      .ForMember(dest => dest.Gender, e => e.MapFrom(src => src.Gender))
                                                      .ForMember(dest => dest.Age, e => e.MapFrom(src => src.Age));
            });
            IMapper mapper = configuration.CreateMapper();

            // 原始数据
            List<Person> list = new List<Person>
            {
                new Person { Id = 1, Name = "张三", Gender = "男", Age = 30, Phone = "1111", Email = "1111@qq.com" },
                new Person { Id = 2, Name = "李四", Gender = "女", Age = 31, Phone = "2222", Email = "2222@qq.com" },
                new Person { Id = 3, Name = "王五", Gender = "男", Age = 32, Phone = "3333", Email = "3333@qq.com" }
            };

            // 转换为DTO
            List<PersonDto> dtos = mapper.Map<List<PersonDto>>(list);

            // DTO转换为原始数据
            List<Person> pos = mapper.Map<List<Person>>(dtos);
            foreach (Person po in pos)
            {
                Console.WriteLine(po.Name + "," + po.Gender + "," + po.Age + "," + po.Phone + "," + po.Email);
            }
            Console.ReadKey();
        }
    }
}

运行结果如下所示:

张三,男,30,,
李四,女,31,,
王五,男,32,,

当然也有简便的方法,AutoMapper提供了一个双向映射的方法ReverseMap(),代码如下:

using AutoMapper;
using System;
using System.Collections.Generic;

namespace MapperApp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 创建对象映射工具
            MapperConfiguration configuration = new MapperConfiguration(options =>
            {
                options.CreateMap<Person, PersonDto>().ForMember(dest => dest.Name, e => e.MapFrom(src => src.Name))
                                                      .ForMember(dest => dest.Gender, e => e.MapFrom(src => src.Gender))
                                                      .ForMember(dest => dest.Age, e => e.MapFrom(src => src.Age))
                                                      .ReverseMap();
            });
            IMapper mapper = configuration.CreateMapper();

            // 原始数据
            List<Person> list = new List<Person>
            {
                new Person { Id = 1, Name = "张三", Gender = "男", Age = 30, Phone = "1111", Email = "1111@qq.com" },
                new Person { Id = 2, Name = "李四", Gender = "女", Age = 31, Phone = "2222", Email = "2222@qq.com" },
                new Person { Id = 3, Name = "王五", Gender = "男", Age = 32, Phone = "3333", Email = "3333@qq.com" }
            };

            // 转换为DTO
            List<PersonDto> dtos = mapper.Map<List<PersonDto>>(list);

            // DTO转换为原始数据
            List<Person> pos = mapper.Map<List<Person>>(dtos);
            foreach (Person po in pos)
            {
                Console.WriteLine(po.Name + "," + po.Gender + "," + po.Age + "," + po.Phone + "," + po.Email);
            }
            Console.ReadKey();
        }
    }
}

运行结果也是一样的:

张三,男,30,,
李四,女,31,,
王五,男,32,,

3.3、AutoMapper中字段名称不一致的处理方法

在某些情况下会存在字段名称不一致的问题,现在修改一下PersonDto的代码,如下所示:

namespace MapperApp
{
    public class PersonDto
    {
        /// <summary>
        /// 姓名
        /// </summary>
        public string PersonName { get; set; }

        /// <summary>
        /// 性别
        /// </summary>
        public string PersonGender { get; set; }

        /// <summary>
        /// 年龄
        /// </summary>
        public int PersonAge { get; set; }

        /// <summary>
        /// 信息
        /// </summary>
        public string PersonInfo { get; set; }
    }
}

每个字段名称都加了前缀,同时新增了一个PersonInfo字段,此时的转换代码如下所示:

using AutoMapper;
using System;
using System.Collections.Generic;

namespace MapperApp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 创建对象映射工具
            MapperConfiguration configuration = new MapperConfiguration(options =>
            {
                options.CreateMap<Person, PersonDto>().ForMember(dest => dest.PersonName, e => e.MapFrom(src => src.Name))
                                                      .ForMember(dest => dest.PersonGender, e => e.MapFrom(src => src.Gender))
                                                      .ForMember(dest => dest.PersonAge, e => e.MapFrom(src => src.Age))
                                                      .ForMember(dest => dest.PersonInfo, e => e.MapFrom(src => $"姓名:{src.Name},性别:{src.Gender},年龄:{src.Age}"))
                                                      .ReverseMap();
            });
            IMapper mapper = configuration.CreateMapper();

            // 原始数据
            List<Person> pos = new List<Person>
            {
                new Person { Id = 1, Name = "张三", Gender = "男", Age = 30, Phone = "1111", Email = "1111@qq.com" },
                new Person { Id = 2, Name = "李四", Gender = "女", Age = 31, Phone = "2222", Email = "2222@qq.com" },
                new Person { Id = 3, Name = "王五", Gender = "男", Age = 32, Phone = "3333", Email = "3333@qq.com" }
            };

            // 转换为DTO
            List<PersonDto> dtos = mapper.Map<List<PersonDto>>(pos);
            foreach (PersonDto dto in dtos)
            {
                Console.WriteLine("------------------------------");
                Console.WriteLine(dto.PersonName + "\n" + dto.PersonGender + "\n" + dto.PersonAge + "\n" + dto.PersonInfo);
            }
            Console.ReadKey();
        }
    }
}

运行结果如下所示:

------------------------------
张三
男
30
姓名:张三,性别:男,年龄:30
------------------------------
李四
女
31
姓名:李四,性别:女,年龄:31
------------------------------
王五
男
32
姓名:王五,性别:男,年龄:32

其实处理方法很简单,就是调用ForMember方法指定要映射的字段名称即可。

3.4、AutoMapper中的空值处理

在某些情况下,源数据中的部分字段值可能为空,例如下面的代码中两条记录的Gender值为空:

List<Person> pos = new List<Person>
{
    new Person { Id = 1, Name = "张三", Gender = null, Age = 30, Phone = "1111", Email = "1111@qq.com" },
    new Person { Id = 2, Name = "李四", Gender = "女", Age = 31, Phone = "2222", Email = "2222@qq.com" },
    new Person { Id = 3, Name = "王五", Gender = null, Age = 32, Phone = "3333", Email = "3333@qq.com" }
};

此时我们希望转换后的实体能够使用一些特定值来代替空值,例如Gender为空时显示性别未知AutoMapper支持在转换规则中使用NullSubstitute方法对空值进行处理,代码如下:

using AutoMapper;
using System;
using System.Collections.Generic;

namespace MapperApp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 创建对象映射工具
            MapperConfiguration configuration = new MapperConfiguration(options =>
            {
                options.CreateMap<Person, PersonDto>().ForMember(dest => dest.Name, e => e.MapFrom(src => src.Name))
                                                      .ForMember(dest => dest.Gender, e => e.NullSubstitute("性别未知"))
                                                      .ForMember(dest => dest.Age, e => e.MapFrom(src => src.Age))
                                                      .ReverseMap();
            });
            IMapper mapper = configuration.CreateMapper();

            // 原始数据
            List<Person> pos = new List<Person>
            {
                new Person { Id = 1, Name = "张三", Gender = null, Age = 30, Phone = "1111", Email = "1111@qq.com" },
                new Person { Id = 2, Name = "李四", Gender = "女", Age = 31, Phone = "2222", Email = "2222@qq.com" },
                new Person { Id = 3, Name = "王五", Gender = null, Age = 32, Phone = "3333", Email = "3333@qq.com" }
            };

            // 转换为DTO
            List<PersonDto> dtos = mapper.Map<List<PersonDto>>(pos);
            foreach (PersonDto dto in dtos)
            {
                Console.WriteLine(dto.Name + "," + dto.Gender + "," + dto.Age);
            }
            Console.ReadKey();
        }
    }
}

运行结果如下所示:

张三,性别未知,30
李四,女,31
王五,性别未知,32

3.5、AutoMapper中映射前后的处理

AutoMapper支持在映射前后对数据进行操作。BeforeMap允许开发者在映射之前进行操作,AfterMap允许开发者在映射之后进行操作,下面的代码演示了在映射之前年龄增加10岁,映射之后再将年龄增加10岁:

using AutoMapper;
using System;
using System.Collections.Generic;

namespace MapperApp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 创建对象映射工具
            MapperConfiguration configuration = new MapperConfiguration(options =>
            {
                options.CreateMap<Person, PersonDto>().ForMember(dest => dest.Name, e => e.MapFrom(src => src.Name))
                                                      .ForMember(dest => dest.Gender, e => e.MapFrom(src => src.Gender))
                                                      .ForMember(dest => dest.Age, e => e.MapFrom(src => src.Age))
                                                      .BeforeMap((src, dest) =>
                                                      {
                                                          // 映射之前年龄增加10岁
                                                          src.Age += 10;
                                                      })
                                                      .AfterMap((src, dest) =>
                                                      {
                                                          // 映射之后年龄增加10岁
                                                          dest.Age += 10;
                                                      })
                                                      .ReverseMap();
            });
            IMapper mapper = configuration.CreateMapper();

            // 原始数据
            List<Person> pos = new List<Person>
            {
                new Person { Id = 1, Name = "张三", Gender = "男", Age = 30, Phone = "1111", Email = "1111@qq.com" },
                new Person { Id = 2, Name = "李四", Gender = "女", Age = 31, Phone = "2222", Email = "2222@qq.com" },
                new Person { Id = 3, Name = "王五", Gender = "男", Age = 32, Phone = "3333", Email = "3333@qq.com" }
            };

            // 转换为DTO
            List<PersonDto> dtos = mapper.Map<List<PersonDto>>(pos);
            foreach (PersonDto dto in dtos)
            {
                Console.WriteLine(dto.Name + "," + dto.Gender + "," + dto.Age);
            }
            Console.ReadKey();
        }
    }
}

运行结果如下所示:

张三,男,50
李四,女,51
王五,男,52

3.6、AutoMapper中的条件过滤

AutoMapper也支持条件过滤。这里的过滤并不是指剔除数据记录,而是隐藏被过滤的字段值。下面代码演示了当Gender="男"时才显示Gender字段值,主要通过Condition方法实现:

using AutoMapper;
using System;
using System.Collections.Generic;

namespace MapperApp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 创建对象映射工具
            MapperConfiguration configuration = new MapperConfiguration(options =>
            {
                options.CreateMap<Person, PersonDto>().ForMember(dest => dest.Name, e => e.MapFrom(src => src.Name))
                                                      .ForMember(dest => dest.Gender, e => e.Condition(src => src.Gender == "男"))
                                                      .ForMember(dest => dest.Age, e => e.MapFrom(src => src.Age))
                                                      .ReverseMap();
            });
            IMapper mapper = configuration.CreateMapper();

            // 原始数据
            List<Person> pos = new List<Person>
            {
                new Person { Id = 1, Name = "张三", Gender = "男", Age = 30, Phone = "1111", Email = "1111@qq.com" },
                new Person { Id = 2, Name = "李四", Gender = "女", Age = 31, Phone = "2222", Email = "2222@qq.com" },
                new Person { Id = 3, Name = "王五", Gender = "男", Age = 32, Phone = "3333", Email = "3333@qq.com" }
            };

            // 转换为DTO
            List<PersonDto> dtos = mapper.Map<List<PersonDto>>(pos);
            foreach (PersonDto dto in dtos)
            {
                Console.WriteLine(dto.Name + "," + dto.Gender + "," + dto.Age);
            }
            Console.ReadKey();
        }
    }
}

运行结果如下所示,可以发现李四的性别并未显示出来:

张三,男,30
李四,,31
王五,男,32

3.7、AutoMapper映射模块的单独配置

在实际开发过程中,为了方便后续的维护和管理,我们一般会把AutoMapper的配置规则写在一个单独的类中,具体方法如下,首先新建ObjectMappingProfile类,该类继承Profile,然后在构造函数中定义转换规则,代码如下:

using AutoMapper;

namespace MapperApp
{
    public class ObjectMappingProfile : Profile
    {
        public ObjectMappingProfile()
        {
            CreateMap<Person, PersonDto>().ForMember(dest => dest.Name, e => e.MapFrom(src => src.Name))
                                          .ForMember(dest => dest.Gender, e => e.MapFrom(src => src.Gender))
                                          .ForMember(dest => dest.Age, e => e.MapFrom(src => src.Age))
                                          .ReverseMap();
        }
    }
}

然后通过AddProfile方法将规则文件加载进来即可,代码如下:

using AutoMapper;
using System;
using System.Collections.Generic;

namespace MapperApp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 创建对象映射工具
            MapperConfiguration configuration = new MapperConfiguration(options => options.AddProfile(new ObjectMappingProfile()));
            IMapper mapper = configuration.CreateMapper();

            // 原始数据
            List<Person> pos = new List<Person>
            {
                new Person { Id = 1, Name = "张三", Gender = "男", Age = 30, Phone = "1111", Email = "1111@qq.com" },
                new Person { Id = 2, Name = "李四", Gender = "女", Age = 31, Phone = "2222", Email = "2222@qq.com" },
                new Person { Id = 3, Name = "王五", Gender = "男", Age = 32, Phone = "3333", Email = "3333@qq.com" }
            };

            // 转换为DTO
            List<PersonDto> dtos = mapper.Map<List<PersonDto>>(pos);
            foreach (PersonDto dto in dtos)
            {
                Console.WriteLine(dto.Name + "," + dto.Gender + "," + dto.Age);
            }
            Console.ReadKey();
        }
    }
}

运行结果如下所示:

张三,男,30
李四,女,31
王五,男,32

4、ASP.NET Core中使用AutoMapper

上面的代码都是基于控制台程序,下面来介绍一下如何在ASP.NET Core中使用AutoMapper。还是使用之前的Author数据表。

Author表数据如下:

IdNameGenderAgeEmail
1张三3511111111@qq.com
2李四4022222222@qq.com
3王五3733333333@qq.com

Author代码如下:

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

// Code scaffolded by EF Core assumes nullable reference types (NRTs) are not used or disabled.
// If you have enabled NRTs for your project, then un-comment the following line:
// #nullable disable

namespace App.Models
{
    public partial class Author
    {
        public Author()
        {
            Book = new HashSet<Book>();
        }
        
        [Key]
        public int Id { get; set; }
        [StringLength(20)]
        public string Name { get; set; }
        [StringLength(2)]
        public string Gender { get; set; }
        public int? Age { get; set; }
        [StringLength(30)]
        public string Email { get; set; }
        [InverseProperty("Author")]
        public virtual ICollection<Book> Book { get; set; }
    }
}

4.1、引入AutoMapper组件

使用NuGet引入AutoMapper组件:

AutoMapper
AutoMapper.Extensions.Microsoft.DependencyInjection

在这里插入图片描述

4.2、创建DTO实体类

新建实体类AuthorDto,代码如下:

namespace App.Dtos
{
    public class AuthorDto
    {
        public string Name { get; set; }
        public string Gender { get; set; }
        public string Email { get; set; }
    }
}

4.3、配置AutoMapper转换规则

添加ObjectMappingProfile类配置映射规则,代码如下:

using App.Dtos;
using App.Models;
using AutoMapper;

namespace App
{
    public class ObjectMappingProfile : Profile
    {
        public ObjectMappingProfile()
        {
            CreateMap<Author, AuthorDto>().ForMember(dest => dest.Name, e => e.MapFrom(src => src.Name))
                                          .ForMember(dest => dest.Gender, e => e.MapFrom(src => src.Gender))
                                          .ForMember(dest => dest.Email, e => e.MapFrom(src => src.Email))
                                          .ReverseMap();
        }
    }
}

4.4、注册AutoMapper服务

Startup.cs中添加AutoMapper服务,代码如下:

using App.Context;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace App
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // 添加控制器
            services.AddControllers();

            // 添加数据库上下文
            services.AddDbContext<DaoDbContext>(options =>
            {
                options.UseSqlServer(Configuration.GetConnectionString("ConnectionString"));
            });

            // 添加AutoMapper
            services.AddAutoMapper(typeof(ObjectMappingProfile).Assembly);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();
            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

4.5、注入IMapper接口

最后在Controller的构造函数中注入IMapper接口即可,代码如下:

using App.Context;
using App.Dtos;
using App.Models;
using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;

namespace App.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class AuthorController : ControllerBase
    {
        protected readonly DaoDbContext _dbContext;
        protected readonly IMapper _mapper;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dbContext">数据库上下文</param>
        /// <param name="mapper">对象映射器</param>
        public AuthorController(DaoDbContext dbContext, IMapper mapper)
        {
            _dbContext = dbContext;
            _mapper = mapper;
        }

        /// <summary>
        /// 查询全部Author实体集合
        /// </summary>
        /// <returns>Author实体集合</returns>
        [HttpGet]
        public ActionResult<List<AuthorDto>> GetAuthors()
        {
            List<Author> authors = _dbContext.Set<Author>().ToList();
            return _mapper.Map<List<AuthorDto>>(authors);
        }

        /// <summary>
        /// 根据性别查询Author实体集合
        /// </summary>
        /// <param name="gender">性别</param>
        /// <returns>Author实体集合</returns>
        [HttpGet]
        public ActionResult<List<AuthorDto>> GetAuthorsByGender(string gender)
        {
            if (string.IsNullOrEmpty(gender) || string.IsNullOrWhiteSpace(gender))
            {
                return BadRequest("参数错误");
            }
            List<Author> authors = _dbContext.Set<Author>().Where(p => p.Gender == gender).ToList();
            return _mapper.Map<List<AuthorDto>>(authors);
        }

        /// <summary>
        /// 根据Id查询Author实体
        /// </summary>
        /// <param name="id">Id</param>
        /// <returns>Author实体</returns>
        [HttpGet]
        public ActionResult<AuthorDto> GetAuthorById(int id)
        {
            if (id <= 0)
            {
                return BadRequest("参数错误");
            }
            Author author = _dbContext.Set<Author>().Find(id);
            return _mapper.Map<AuthorDto>(author);
        }
    }
}

GetAuthors运行结果如下所示:

[
    {
        "name": "张三",
        "gender": "男",
        "email": "11111111@qq.com"
    },
    {
        "name": "李四",
        "gender": "女",
        "email": "22222222@qq.com"
    },
    {
        "name": "王五",
        "gender": "男",
        "email": "33333333@qq.com"
    }
]

GetAuthorsByGender运行结果如下所示:

[
    {
        "name": "张三",
        "gender": "男",
        "email": "11111111@qq.com"
    },
    {
        "name": "王五",
        "gender": "男",
        "email": "33333333@qq.com"
    }
]

GetAuthorById运行结果如下所示:

{
    "name": "张三",
    "gender": "男",
    "email": "11111111@qq.com"
}

以上就是在ASP.NET Core中使用AutoMapper的具体流程。

5、结语

本文主要介绍了AutoMapper的部分使用方法。有一些同志也问过:项目中一定要使用AutoMapper在对象之间转来转去吗?以个人体验来说,我认为不一定非要使用AutoMapper。对于一些赶进度、规模又不是很大的工程来说,建立DTO对象反而会增加工作量,还不如直接使用EFCore生成的实体类,这样方便又快速。如果项目规模到达一定程度,同时开发组里希望遵循一定的项目规范,那么建立诸如DTOVO之类的实体类,通过AutoMapper实现相互转换还是有必要的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值