Asp.NetCore之AutoMapper基础篇

应用场景

       现在由于前后端技术的分离,后端程序员在使用ORM框架开发后台API接口的时候,往往会将数据库的“数据模型”直接提供给前端。而大多数时候,可能这些数据并不能够满足前端展示的需求,有时候可能需要在“数据模型”的基础上,加几个字段或者改几个字段展示名称或者字段展示风格,以满足前端“视图模型”的需求。遇到这种情况,后端往往需要同时定义“数据模型”和“视图模型”,并在两者之间做大量的字段赋值工作,如果“数据模型”和“视图模型”差别不大的话,这无疑很耗费心力,而且容易出错。

        我们先来理解两个概念“数据模型”和“视图模型”:

        “数据模型”:最简单的一种“”数据模型“”你可以把它当成是数据库表对象模型(数据模型字段一一对应数据库表结构,是数据库表的一种表现形式),使用ORM的小伙伴应该都知道,通过ORM数据库模型可以直接映射到数据表结构,可以直接操作数据库。

        “视图模型”:通过这个名称我们很容易理解,视图模型是前端展示页面中所需元素的一个集合。

        当我们将“数据模型”转换成“视图模型”提供给前端的时候,务必会产生大量的模型字段赋值的工作,模型很大的时候是不是想死的心都有了。。。AutoMapper的出现正是解决了两个模型之间枯燥无味的转换工作,用户只需要简单设置一下转换规则即可,避免了我们每次都采用手工编写代码的方式进行转换。

.NetCore快速上手

1.创建项目

 

添加数据库“数据模型”:

    /// <summary>
    /// 订单表
    /// </summary>
    public class Order
    {
        /// <summary>
        /// ID
        /// </summary>
        public int Id { get; set; }
        /// <summary>
        /// 订单名称
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 价格
        /// </summary>
        public decimal Price { get; set; }

        public DateTime CreateTime { get; set; }

        public int CustomId { get; set; }
}
    /// <summary>
    /// 订单子表
    /// </summary>
    public class OrderItem
    {
        public int ItemId { get; set; }
        public int OrderId { get; set; }
        public decimal Price { get; set; }
        /// <summary>
        /// 创建时间
        /// </summary>
        public DateTime CreateTime { get; set; }
    }

 2.添加AutoMapper依赖包

第二个包是.NetCore依赖注入使用。

3.项目中添加“视图模型”

    /// <summary>
    /// 订单映射模型
    /// </summary>
    public class OrderDTO
    {
        public int Id { get; set; }
        /// <summary>
        /// 订单名称
        /// </summary>
        public string OrderName { get; set; }
        public decimal Price { get; set; }
        public DateTime CreateTime { get; set; }
        public int CustomId { get; set; }
    }
    /// <summary>
    /// 订单子表映射模型
    /// </summary>
    public class OrderItemDTO
    {
        public int ItemId { get; set; }
        public int OrderId { get; set; }
        public decimal Price { get; set; }
        /// <summary>
        /// 创建时间
        /// </summary>
        public string CreateTime { get; set; }
    }

 4.添加自定义AutoMapper映射文件(OrderMapperProfile)

 在.NetCore我们需要创建一个自己的映射配置类,该配置类必须继承AutoMapper的Profile抽象类,然后才能通过依赖注入AutoMapper的方式调用。

    /// <summary>
    /// 映射配置
    /// </summary>
    public class OrderMapperProfile : Profile
    {
        public OrderMapperProfile()
        {
            //字段名称不一致 Name映射到OrderName
            CreateMap<Order, OrderDTO>().ForMember(dest => dest.OrderName, src => src.MapFrom(s => s.Name));
            //字段类型不一致 DateTime映射到String
            CreateMap<OrderItem, OrderItemDTO>().ForMember(dest => dest.CreateTime, src => src.ConvertUsing(new FormatConvert()));
        }
    }

    /// <summary>
    /// DateTime映射到String
    /// </summary>
    public class FormatConvert : IValueConverter<DateTime, string>
    {
        public string Convert(DateTime sourceMember, ResolutionContext context)
        {
            if (sourceMember == null)
                return DateTime.Now.ToString("yyyyMMddHHmmssfff");
            return sourceMember.ToString("yyyyMMddHHmmssfff");
        }
    }

 1)自定义映射文件需继承AutoMapper抽象类“Profile”

 2)调用方法CreateMap实现模型映射

public IMappingExpression<TSource, TDestination> CreateMap<TSource, TDestination>(MemberList memberList);
public IMappingExpression<TSource, TDestination> CreateMap<TSource, TDestination>();

 TSource代表“数据模型”,TDestination代表“视图模型”,MemberList可选,默认0

    public enum MemberList
    {
        /// <summary>
        /// 检查是否已映射所有目标成员
        /// </summary>
        Destination = 0,

        /// <summary>
        /// 检查是否已映射所有源成员
        /// </summary>
        Source = 1,

        /// <summary>
        /// 既不检查源成员也不检查目标成员,跳过验证
        /// </summary>
        None = 2
    }

例如:

CreateMap<Order, OrderDTO>();

3)调用ForMember自定义两个模型之间映射规则。

     因为 AutoMapper 默认是通过匹配字段名称和类型进行自动匹配,所以如果你进行转换的两个类的中的某些字段名称不一样,这里我们就需要进行手动的编写转换规则。

IMappingExpression<TSource, TDestination> ForMember<TMember>(Expression<Func<TDestination, TMember>> destinationMember, Action<IMemberConfigurationExpression<TSource, TDestination, TMember>> memberOptions);

     其中比较常用的:

      1.两个映射模型属性/字段名称不一致。

//字段名称不一致 源类型Name映射到目标类型OrderName
CreateMap<Order, OrderDTO>().ForMember(dest => dest.OrderName, src => src.MapFrom(s => s.Name));

      2.两个映射模型属性/字段数据类型或展现形式不一致。

//字段类型不一致 源类型DateTime映射到目标类型String字符串
CreateMap<OrderItem, OrderItemDTO>().ForMember(dest => dest.CreateTime, src => src.ConvertUsing(new FormatConvert()));

ConvertUsing()方法中需实现成员参数接口IValueConverter中的Convert方法,实现自定义转换

void ConvertUsing<TSourceMember>(IValueConverter<TSourceMember, TMember> valueConverter);
    public interface IValueConverter<in TSourceMember, out TDestinationMember>
    {
        TDestinationMember Convert(TSourceMember sourceMember, ResolutionContext context);
    }

自定义实现接口Convert方法,实现DateTime转string字符串:

    /// <summary>
    /// DateTime映射到String
    /// </summary>
    public class FormatConvert : IValueConverter<DateTime, string>
    {
        public string Convert(DateTime sourceMember, ResolutionContext context)
        {
            if (sourceMember == null)
                return DateTime.Now.ToString("yyyyMMddHHmmssfff");
            return sourceMember.ToString("yyyyMMddHHmmssfff");
        }
    }

5.配置好映射文件后,.NetCore中需要注册我们刚才的自定义Profile

 //注册AutoMapper
 //方式1  指定映射配置文件  多个可用数组表示
 services.AddAutoMapper(typeof(OrderMapperProfile));
 //方式2   注册程序集下面所有映射文件
 services.AddAutoMapper(Assembly.Load("程序集dll名称"))

6.最后我们可以通过注入AutoMapper的方式,在业务逻辑层使用我们的自定义映射配置文件Profile

public class OrderService : IOrderService
    {
        private readonly IMapper mapper;
        /// <summary>
        /// 构造函数注入Mapper
        /// </summary>
        /// <param name="_dBContext"></param>
        /// <param name="_mapper"></param>
        public OrderService(IMapper _mapper)
        {
            mapper = _mapper;
        }
        /// <summary>
        /// 名称不一致  映射
        /// </summary>
        /// <returns></returns>
        public async Task<List<OrderDTO>> Query()
        {
            //ORM获取数据模型数据
            var orderList = await dBContext.DB.Queryable<Order>().ToListAsync();
            //DTO映射
            var orderDtoList = mapper.Map<List<OrderDTO>>(orderList);
            return await Task.FromResult(orderDtoList);
        }

        /// <summary>
        /// 数据类型/展现形式不一致 映射
        /// </summary>
        /// <returns></returns>
        public async Task<List<OrderItemDTO>> QueryItem()
        {
            var orderList = await dBContext.DB.Queryable<OrderItem>().ToListAsync();
            var orderDtoList = mapper.Map<List<OrderItemDTO>>(orderList);
            return await Task.FromResult(orderDtoList);
        }
    }

7.实现效果

 1)“数据模型”Order类型中的Name属性值  映射到  “视图模型”OrderDTO类型中的OrderName

 

  2)“数据模型”OrderItem类型中的CreateTime属性DateTime数据类型  映射到  “视图模型”OrderItemDTO类型中的CreateTime属性string数据类型

 小结

      本篇文章主要简单介绍下在Asp.NetCore项目中如何快速上手AutoMapper,总体来看想要上手还是比较简单,只要掌握好几个经常使用的映射规则就可以了。当然,AutoMapper为我们准备了各种自定规则的入口,有兴趣的小伙伴可以下载源码,源码中包含了很多测试用例,学习起来也比较容易理解。附上AutoMapper源码地址:https://github.com/AutoMapper/AutoMapper

原文地址:https://www.cnblogs.com/chenxf1117/p/14069111.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


数组的定义 Dim MyArray MyArray = Array(1‚5‚123‚12‚98) 可扩展数组 Dim MyArray() for i = 0 to 10
\'参数: \'code:要检测的代码 \'leixing:html或者ubb \'nopic:代码没有图片时默认值
演示效果: 代码下载: 点击下载
环境:winxp sp2 ,mysql5.0.18,mysql odbc 3.51 driver 表采用 myisam引擎。access 2003  不同的地方: 
其实说起AJAX的初级应用是非常简单的,通俗的说就是客户端(javascript)与服务端(asp或php等)脚本语言的数据交互。
<% ’判断文件名是否合法 Function isFilename(aFilename)  Dim sErrorStr,iNameLength,i  isFilename=TRUE
在调用的时候加入判断就行了. {aspcms:navlist type=0 } {if:[navlist:i]<6} < li><a href=\"[navlist:link]\" target=\"_top\">[navlist:name]</a> </li>
导航栏调用 {aspcms:navlist type=0}     <a href=\"[navlist:link]\">[navlist:name]</a>
1.引入外部文件: {aspcms:template src=infobar.html} 2.二级下拉菜单 <ul class=\"nav\">
downpic.asp页面:  <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
Cookies是数据包,可以让网页具有记忆功能,在某台电脑上记忆一定的信息。Cookies的工作原理是,第一次由服务器端写入到客户端的系统中。以后每次访问这个网页,都是先由客户端将Cookies发送到服务器端,再由服务器端
很简单,在需要调用的地方用这种模式 {aspcms:content sort={aspcms:sortid} num=17 order=isrecommend}
网站系统使用ACCESS数据库时,查询时怎么比较日期和时间呢?为什么常常比较出来却是错误的呢?比如早的日期比迟的日期大?
str1=\"1235,12,23,34,123,21,56,74,1232\" str2=\"12\" 问题:如何判断str2是否存在str1中,要求准确找出12,不能找出str1中的1235、123、1232
实例为最新版本的kindeditor 4.1.5. 主要程序: <% Const sFileExt=\"jpg|gif|bmp|png\" Function ReplaceRemoteUrl(sHTML,sSaveFilePath,sFileExt)
用ASP实现搜索引擎的功能是一件很方便的事,可是,如何实现类似3721的智能搜索呢?比如,当在搜索条件框内输入“中国人民”时,自动从中提取“中国”、“人民”等关键字并在数据库内进行搜索。看完本文后,你就可以发
首先感谢ASPCMS官网注册用户xing0203的辛苦付出!一下为久忆YK网络转载原创作者xing0203的文章内容!为了让小白更加清楚的体验替换过程,久忆YK对原文稍作了修改!
数据库连接: <% set conn=server.createobject(\"adodb.connection\") conn.open \"driver={microsoft access driver (*.mdb)};dbq=\"&server.mappath(\"数据库名\")
第1步:修改plugins下的image/image.js 找到\'<input type=\"button\" class=\"ke-upload-button\" value=\"\' + lang.upload + \'\" />\',
asp函数: <% Const sFileExt=\"jpg|gif|bmp|png\" Function ReplaceRemoteUrl(sHTML,sSaveFilePath,sFileExt)