ASP.NET Core 中的对象映射之 AutoMapper

目录

  • AutoMapper 简介
  • AutoMapper 使用
    • 初始化
    • Profile设置
    • 扁平化映射
    • 集合映射
    • 投影
    • 条件映射
    • 值转换
    • 设置转换前后行为
    • 配置验证及设置
    • 反向映射
    • 自定义转换器
    • 自定义解析器
  • 参考

AutoMapper 简介

AutoMapper是一个对象映射器,它可以将一种类型的对象转换为另一种类型的对象。

它提供了映射规则及操作方法,使我们不用过多配置就可以映射两个类, 可以帮我们免于编写无聊的映射代码. 在代码层与层之间隔离模型model上非常有用.

AutoMapper 使用

初始化

创建两个简单的类用于测试:

public class UserEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class UserDTO
{
    public int Id { get; set; }
    public string Name { get; set; }
}

AutoMapper可以使用静态类和实例方法来创建映射.

  • 静态类方式

    Mapper.Initialize(cfg => cfg.CreateMap<UserEntity, UserDTO>());
    var userDTO = Mapper.Map<UserDTO>(user);
  • 实例方式
    var config = new MapperConfiguration(cfg => cfg.CreateMap<UserEntity, UserDTO>());
    var mapper = config.CreateMapper();
    
    var userDTO = mapper.Map<UserDTO>(user);
  • 依赖注入

    使用扩展 AutoMapper.Extensions.Microsoft.DependencyInjection 来实现AutoMapper的依赖注入. 本质是注册一个MapperConfiguration的单例和IMapper的scope实例, 通过程序集扫描添加AutoMapper的相关配置和映射.

    IServiceCollection services = new ServiceCollection();
    services.AddAutoMapper();
    
    var provider = services.BuildServiceProvider();
    using (var scope = provider.CreateScope())
    {
        var mapper = scope.ServiceProvider.GetService<IMapper>();
        var userDTO = mapper.Map<UserDTO>(user);
    }

Profile设置

可以使用Profie配置来实现映射关系, 然后通过AddProfile添加.

public class UserProfile : Profile
{
    public UserProfile()
    {
        CreateMap<UserEntity, UserDTO>();
    }
}

var config = new MapperConfiguration(cfg => cfg.AddProfile<UserProfile>());

扁平化映射

AutoMapper支持扁平化映射, 它会根据Pascal命名方式分割目标字段为单个单词, 可自动映射属性名+内嵌属性名. 如下例AutoMapper自动映射UserEntity.Address.City -> UserDTO.AddressCity。

public class UserEntity
{
    public int Id { get; set; }
    public string Name { get; set; }

    public Address Address { get; set; }
}

public class Address
{
    public string City { get; set; }
    public string Country { get; set; }
}

public class UserDTO
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string AddressCity { get; set; }
    public string AddressCountry { get; set; }
}

集合映射

AutoMapper除了可以映射单个对象外,也可以映射集合对象。

CreateMap<UserEntity, UserDTO>();

var userList = new List<UserEntity> {
    new UserEntity { Id = 1, Name="Test1" },
    new UserEntity { Id = 2, Name="Test2" },
};
var dtoList = mapper.Map<List<UserDTO>>(userList);
public class UserEntity
{
    public int Id { get; set; }
    public string Name { get; set; }

    public List<AddressEntity> AddressList { get; set; }
}

public class AddressEntity
{
    public string City { get; set; }
    public string Country { get; set; }
}

public class UserDTO
{
    public int Id { get; set; }
    public string Name { get; set; }

    public List<AddressDTO> AddressList { get; set; }
}

public class AddressDTO
{
    public string City { get; set; }
    public string Country { get; set; }
}

CreateMap<AddressEntity, AddressDTO>();
CreateMap<UserEntity, UserDTO>();

var user = new UserEntity
{
    Id = 1,
    Name = "Test",
    AddressList = new List<AddressEntity>
    {
        new AddressEntity { City = "ShangHai", Country = "China"},
        new AddressEntity { City = "BeiJing", Country = "China"}
    }
};

var userDTO = mapper.Map<UserDTO>(user);

投影

当把一个源值投影到一个不精准匹配源结构的目标值时,使用MapFrom指明成员映射定义。

public class UserEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime BirthDate { get; set; }
}

public class UserDTO
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string BirthYear { get; set; }
    public string BirthMonth { get; set; }
}

public class UserProfile : Profile
{
    public UserProfile()
    {
        CreateMap<UserEntity, UserDTO>()
            .ForMember(d => d.BirthYear, o => o.MapFrom(s => s.BirthDate.Year))
            .ForMember(d => d.BirthMonth, o => o.MapFrom(s => s.BirthDate.Month));
    }
}

var user = new UserEntity
{
    Id = 1,
    Name = "Test",
    BirthDate = DateTime.Today,
};

var userDTO = mapper.Map<UserDTO>(user);

条件映射

有些情况下,我们将只满足映射条件的才添加到属性上.

public class UserProfile : Profile
{
    public UserProfile()
    {
        CreateMap<UserEntity, UserDTO>()
            .ForMember(d => d.Id, o => o.Condition(s => s.Id > 1));
    }
}

值转换

AutoMapper可以配置值转换和空值替换

public class UserProfile : Profile
{
    public UserProfile()
    {
        CreateMap<UserEntity, UserDTO>()
            .ForMember(d => d.Name, o => o.NullSubstitute("Default Name"))
            .ForMember(d => d.Name, o => o.AddTransform(val => string.Format("Name: {0}", val)));
    }
}

设置转换前后行为

有时候,在映射发生之前或之后,可能需要执行一些自定义的逻辑。

public class UserProfile : Profile
{
    public UserProfile()
    {
        CreateMap<UserEntity, UserDTO>()
            .BeforeMap((s, d) => s.BirthDate = s.BirthDate.AddYears(-12))
            .AfterMap((s, d) => d.BirthMonth = "July");
    }
}

配置验证及设置

配置了映射,但是如何确定是否映射成功或者是否有字段没有映射呢?可以使用mapper.ConfigurationProvider.AssertConfigurationIsValid()来验证是否映射成功。但也可以指定单个字段不验证.

public class UserProfile : Profile
{
    public UserProfile()
    {
        CreateMap<UserEntity, UserDTO>()
            .ForMember(d => d.NickName, o => o.Ignore());
    }
}

反向映射

从6.1.0开始,AutoMapper通过ReverseMap可以实现反向映射。使用ReverseMap, 不用再创建DTO -> Entity的映射, 而且还能保留正向的映射规则。

public class UserProfile : Profile
{
    public UserProfile()
    {
        CreateMap<UserEntity, UserDTO>()
            .ReverseMap();
    }
}

自定义转换器

有些情况下目标字段类型和源字段类型不一致,可以通过类型转换器实现映射,类型转换器有三种实现方式:

void ConvertUsing(Func<TSource, TDestination> mappingFunction);
void ConvertUsing(ITypeConverter<TSource, TDestination> converter);
void ConvertUsing<TTypeConverter>() where TTypeConverter : ITypeConverter<TSource, TDestination>;

自定义解析器

某些情况下,解析规则会很复杂,使用自带的解析规则无法实现。这时可以自定义解析规则,可以通过以下三种方式使用自定义的解析器:

ResolveUsing<TValueResolver>
ResolveUsing(typeof(CustomValueResolver))
ResolveUsing(aValueResolverInstance)
public class UserEntity
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class UserDTO
{
    public string Name { get; set; }
}

public class UserNameResolver : IValueResolver<UserEntity, UserDTO, string>
{
    public string Resolve(UserEntity source, UserDTO destination, string destMember, ResolutionContext context)
    {
        if (source != null && !string.IsNullOrEmpty(source.FirstName) && !string.IsNullOrEmpty(source.LastName))
        {
            return string.Format("{0} {1}", source.FirstName, source.LastName);
        }

        return string.Empty;
    }
}

public class UserProfile : Profile
{
    public UserProfile()
    {
        CreateMap<UserEntity, UserDTO>()
            .ForMember(d => d.Name, o => o.ResolveUsing<UserNameResolver>());
    }
}

参考

原文地址:https://www.cnblogs.com/royzshare/p/9951683.html

时间: 2024-10-21 17:44:56

ASP.NET Core 中的对象映射之 AutoMapper的相关文章

ASP.NET Core Web 应用程序系列(五)- 在ASP.NET Core中使用AutoMapper进行实体映射

原文:ASP.NET Core Web 应用程序系列(五)- 在ASP.NET Core中使用AutoMapper进行实体映射 本章主要简单介绍下在ASP.NET Core中如何使用AutoMapper进行实体映射.在正式进入主题之前我们来看下几个概念: 1.数据库持久化对象PO(Persistent Object):顾名思义,这个对象是用来将我们的数据持久化到数据库,一般来说,持久化对象中的字段会与数据库中对应的 table 保持一致. 2.视图对象VO(View Object):视图对象 V

ASP.NET Core中如何针对一个使用HttpClient对象的类编写单元测试

原文地址: How to unit test a class that consumes an HttpClient with IHttpClientFactory in ASP.NET Core? 作者: Anthony Giretti 译者: Lamond Lu 介绍 几年前,微软引入了HttpClient类来替代HttpWebRequest来发送Web请求.这个新的类更易于使用,更加简洁,更具有异步性,且易于扩展. HttpClient类有一个可以接受HttpMessageHandler类

ASP.NET Core中的依赖注入(2):依赖注入(DI)

参考页面: http://www.yuanjiaocheng.net/ASPNET-CORE/project-layout.html http://www.yuanjiaocheng.net/ASPNET-CORE/projectjson.html http://www.yuanjiaocheng.net/ASPNET-CORE/core-configuration.html http://www.yuanjiaocheng.net/ASPNET-CORE/core-middleware.htm

ASP.NET Core中的依赖注入(5): ServiceProvider实现揭秘 【总体设计 】

本系列前面的文章我们主要以编程的角度对ASP.NET Core的依赖注入系统进行了详细的介绍,如果读者朋友们对这些内容具有深刻的理解,我相信你们已经可以正确是使用这些与依赖注入相关的API了.如果你还对这个依赖注入系统底层的实现原理具有好奇心,可以继续阅读这一节的内容. 目录一.ServiceCallSite 二.Service 三.ServiceEntry 四.ServiceTable 五.ServiceProvider 作为DI容器的体现,ServiceProvider是ASP.NET Co

ASP.NET Core中使用GraphQL - 第三章 依赖注入

ASP.NET Core中使用GraphQL ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间件 SOLID原则中的D表示依赖倒置原则.这个原则的内容是: 上层模块不应该直接依赖底层模块,而应该依赖其抽象 抽象不应该依赖于细节, 细节应该依赖抽象 来源:WIKIPEDIA 在一个模块中创建一个其他模块的实例会导致这个模块与其他模块之间的紧耦合. 为了让不同的模块解耦,我们需要遵循依赖倒置原则.按照这种

ASP.NET Core中使用GraphQL - 第五章 字段, 参数, 变量

ASP.NET Core中使用GraphQL ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间件 ASP.NET Core中使用GraphQL - 第三章 依赖注入 ASP.NET Core中使用GraphQL - 第四章 GrahpiQL 字段# 我们已经很好的理解了GraphQL中的字段.在之前HelloWorldQuery的例子中,我们添加了2个字段hello和howdy. 它们都是标量字段.正

Asp.net core中的websocket

Websocket是html5后的产物,对于asp.net core中也得到了支持,首先在NuGet中添加Microsoft.AspNetCore.WebSockets的引用(现在是1.0.1版本,2017年3月7日发布的). 首先在Configure中添加中间件 //添加websocket中间件 app.UseWebSockets(); 接下来就要定义自己处理websocket的中间件了,代码如下: using Microsoft.AspNetCore.Http; using System;

ASP.NET Core中的依赖注入(5): ServiceProvider实现揭秘 【解读ServiceCallSite 】

通过上一篇的介绍我们应该对实现在ServiceProvider的总体设计有了一个大致的了解,但是我们刻意回避一个重要的话题,即服务实例最终究竟是采用何种方式提供出来的.ServiceProvider最终采用何种方式提供我们所需的服务实例取决于最终选择了怎样的ServiceCallSite,而服务注册是采用的ServiceDescriptor有决定了ServiceCallSite类型的选择.我们将众多不同类型的ServiceCallSite大体分成两组,一组用来创建最终的服务实例,另一类则与生命周

ASP.NET Core中的依赖注入(5):ServicePrvider实现揭秘【补充漏掉的细节】

到目前为止,我们定义的ServiceProvider已经实现了基本的服务提供和回收功能,但是依然漏掉了一些必需的细节特性.这些特性包括如何针对IServiceProvider接口提供一个ServiceProvider对象,何创建ServiceScope,以及如何提供一个服务实例的集合. 一.提供一个ServiceProvider对象 我们知道当将服务类型指定为IServiceProvider接口并调用ServiceProvider的GetService方法是,ServiceProvider对象本