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

news2024/11/29 16:36: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实现相互转换还是有必要的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/152641.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C进阶】指针和数组综合题

家人们欢迎来到小姜的世界&#xff0c;<<点此>>传送门 这里有详细的关于C/C/Linux等的解析课程&#xff0c;家人们赶紧冲鸭&#xff01;&#xff01;&#xff01; 客官&#xff0c;码字不易&#xff0c;来个三连支持一下吧&#xff01;&#xff01;&#xff01;关注…

设计模式-工厂模式(Java)

工厂方法模式 工厂方法模式&#xff1a;Factory Method 事物是发展的&#xff0c;随着事物的不断发展&#xff0c;原有的对象会随着发展不断变化&#xff0c;或增或减。 工厂方法模式提供的一种封装机制&#xff0c;隔离出了那些易变动的对象。这个时候需求的变动不再影响之前…

Mybatis-Plus中的条件查询-DQL编程

条件构造器 | MyBatis-Plus 当需要进行一些复杂的条件查询时&#xff0c;则需使用wrapper&#xff0c;来编辑这些条件 1、条件查询 ①allEq() 即是where后面的等于"",该方法的后的所有参数都会被以"and"的形式进行连接 QueryWrapper qw1 new QueryWra…

Go语言设计与实现 -- 栈空间管理

寄存器 图片来自于面向信仰编程 Go 语言的汇编代码包含 BP 和 SP 两个栈寄存器&#xff0c;它们分别存储了栈的基址指针和栈顶的地址&#xff0c;栈内存与函数调用的关系非常紧密&#xff0c;我们在函数调用一节中曾经介绍过栈区&#xff0c;BP 和 SP 之间的内存就是当前函数的…

数智化转型进入“精装时代”,容联云助力千行百业加速上云用数赋智

随着产业数字化向前推进&#xff0c;企业引入数字技术的需求和热情十分充足&#xff0c;但要把技术下沉到市场中&#xff0c;还存在一个关键的矛盾&#xff1a;交付能力。千行百业&#xff0c;尤其是传统实体经济从业者&#xff0c;对数智化所需要的5G、IOT、AI、大数据、云计算…

canvas入门教学(5)运动小球屏保特效与下雪特效渲染

本节我们来学习两个例子,第一个例子是如下图这样的,全屏各色各样的小球随机运动,碰撞到屏幕边缘再反弹回来的特效,我们一步一步带着大家来学习这个canvas应用。 首先呢,基于上一个教程的例子,我们需要基础的构建圆, 上节教程在这里 并且呢我们要重复的多次的构建半径…

OVN实验----L2互通

概述 尽量少贴概念&#xff0c;只同步一些必要的名词。 central: 可以看做中心节点&#xff0c;central节点组件包括OVN/CMS plugin、OVN Northbound DB、ovn-northd、OVN Southbound DB。 hypervisor: 可以看做工作节点&#xff0c;hypervisor节点组件包括ovn-controller、ov…

Target 塔吉特的4种商品编码

Target塔吉特共有4种商品编码&#xff1a;TCIN、DPCI、UPC、SKU&#xff0c;其中DPCI、UPC和TCIN在Target系统中是唯一的ID。在target.com中查看商品时&#xff0c;在任一个商品中下拉进入到商品详情页&#xff08;Item/Detail/Specifications&#xff09;中都可以看到该商品的…

13_5、Java的IO流之转换流的使用

一、转换流涉及到的类&#xff1a;都是字符流InputStreamReader&#xff1a;将输入的字节流转换为输入的字符流。解码&#xff1a;字节、字节数组 ————>字符串、字符数组OutputStreamWrite&#xff1a;将输出的字符流转换为输出的字节流。编码&#xff1a;字符串、字符数…

Linux 网络探测和安全审核工具 nmap 应用实践

对于 nmap&#xff0c;相信很多安全运维人员并不陌生&#xff0c;它曾经在电影《黑客帝国》中出现过&#xff0c; 是黑客和网络安全人员经常用到的工具&#xff0c;本文重点介绍下此工具的实现原理和使用技巧。 nmap 和 Zenmap 简介 nmap 是一款开源免费的网络发现工具&#…

2023兔年大吉HTML,兔兔动态代码「兔了个兔」

文章目录一.2023兔年大吉HTML&#xff0c;兔兔动态代码「兔了个兔」1.1 资源获取和效果预览二.代码讲解&#xff08;主要代码&#xff09;1.1 背景加圆圈圈1.2.兔兔和提示字1.3 JavaScript控制动态一.2023兔年大吉HTML&#xff0c;兔兔动态代码「兔了个兔」 1.1 资源获取和效果…

如何在游戏中实现飘花和落叶效果

本文首发于微信公众号&#xff1a; 小蚂蚁教你做游戏。欢迎关注领取更多学习做游戏的原创教程资料&#xff0c;每天学点儿游戏开发知识。嗨&#xff01;大家好&#xff0c;我是小蚂蚁。今天这篇文章分享一下如何在游戏中实现飘花和落叶的效果&#xff0c;在游戏背景中加入它们&…

FPGA:数字电路简介

文章目录数字电路的历史电子管时代晶体管时代半导体集成电路IC 时代IC的发展阶段EDA (Electronics Design Automation) 技术数字集成电路的分类数字集成电路的集成度分类从器件导电类型不同从器件类型不同数字电路的历史 数字电路是数字计算机和自动控制系统的基础&#xff0c…

[JavaEE初阶] 线程安全问题之内存可见性问题----volatile

读书要趁黑发早,白首不悔少当时 文章目录1. 什么是内存可见性问题2. 避免内存可见性问题-----volatile(易变的)3. 需要注意的点总结1. 什么是内存可见性问题 在线程A在读一个变量的时候,另一个线程B在修改这个变量,所以,线程A读到的值不是修改之后的,是一个未更新的值,读到的值…

先行“蜀道”, 四川农信核心系统分布式转型

作者&#xff1a;四川省农村信用社联合社 张朝辉 桂俊鸿 来源:《金融电子化》 随着四川省联社党委提出“合规银行、智慧银行、主力军银行”三大银行战略。作为四川省业务规模最大的银行业金融机构、全国农信系统“排头兵”的四川农信积极响应&#xff0c;率先于 2018 年 9 月完…

mysql磁盘io

1、磁盘的一些概念 1.1、盘片、片面 和 磁头 硬盘中一般会有多个盘片组成&#xff0c;每个盘片包含两个面&#xff0c;每个盘面都对应地有一个读/写磁头。受到硬盘整体体积和生产成本的限制&#xff0c;盘片数量都受到限制&#xff0c;一般都在5片以内。盘片的编号自下向上从…

Viper渗透框架

文章目录Viper 简介Viper 安装脚本安装手动安装切换到 root 用户执行命令Kali 安装 docker (我已经安装过了&#xff0c;不做演示&#xff0c;命令依次执行即可)安装 docker-compose设置安装目录生成安装目录&#xff0c;并进入安装目录生成 docker-compose.yml设置登录密码写入…

【C++常用算法】STL基础语法学习 | 拷贝算法替换算法

目录 ●copy ●replace ●replace_if ●swap ●copy 1.功能描述&#xff1a; 将容器内指定范围的元素拷贝到另一容器中 2.查看copy定义下底层代码的函数原型&#xff1a; 3.向deque容器中插入10~50五个数&#xff0c;将这五个数拷贝到另一个指定容器中并输出。 #include&…

【生产问题】前端接口请求报blocked:mixed-content

事故现象 客户端反馈系统无法使用。打开页面很多内容无法显示。 f12 显示很多请求都失败了。 定位问题 客户咨询 客户反馈昨天 在nginx 上面配置了https证书。导致了http 请求无法访问。 客户已经在nginx上面配置了https。即 网页端的请求会重定向到https请求上面。那为啥…

无需离开 Visual Studio 即可编写 Markdown

当您想要格式化代码但又不想牺牲易读性时&#xff0c;Markdown 是一个很好的解决方案。GitHub 将其用于自述文件&#xff0c;我们将其用作 Visual Studio 文档的标准。之前收到了不少来自开发者的反馈&#xff0c;大家希望在 Visual Studio 中使用 Markdown 编辑器。在最近的 V…