当前位置: 首页 > 编程日记 > 正文

AutoMapper用法

AutoMapper是对象到对象的映射工具。在完成映射规则之后,AutoMapper可以将源对象转换为目标对象。

作者:齐飞

原文:http://www.qeefee.com/article/automapper

配置AutoMapper映射规则

AutoMapper是基于约定的,因此在实用映射之前,我们需要先进行映射规则的配置。

public class Source
{public int SomeValue { get; set; }public string AnotherValue { get; set; }
}public class Destination
{public int SomeValue { get; set; }
}

在上面的代码中,我们定义了两个类,我们需要将Source类的对象映射到Destination类的对象上面。要完成这个操作,我们需要对AutoMapper进行如下配置:

Mapper.CreateMap<Source, Destination>();

进行一下测试:

Source src = new Source() { SomeValue = 1, AnotherValue = "2" };
Destination dest = Mapper.Map<Destination>(src);ObjectDumper.Write(dest);

我们可以在控制台看到dest对象的属性值:

image

这样我们就完成了一个简单的AutoMapper映射。

Profile的用法

Profile提供了一个命名的映射类,所有继承自Profile类的子类都是一个映射集合。

我们来看一下Profile的用法,这个例子中仍然使用上面的Source类和Destination类。

public class SourceProfile : Profile
{protected override void Configure(){CreateMap<Source, Destination>();}
}

我们可以再Profile中重写Configure方法,从而完成映射规则的配置。从Profile初始化Mapper规则:

Mapper.Initialize(x => x.AddProfile<SourceProfile>());

在一个Profile中,我们可以完成多个、更复杂的规则的约定:

public class Destination2
{public int SomeValue { get; set; }public string AnotherValue2 { get; set; }
}public class SourceProfile : Profile
{protected override void Configure(){//Source->DestinationCreateMap<Source, Destination>();//Source->Destination2CreateMap<Source, Destination2>().ForMember(d => d.AnotherValue2, opt =>{opt.MapFrom(s => s.AnotherValue);});}
}

AutoMapper最佳实践

这段内容将讨论AutoMapper的规则写在什么地方的问题。

在上一段中,我们已经知道了如何使用AutoMapper进行简单的对象映射,但是,在实际的项目中,我们会有很多类进行映射(从Entity转换为Dto,或者从Entity转换为ViewModel等),这么多的映射如何组织将成为一个问题。

首先我们需要定义一个Configuration.cs的类,该类提供AutoMapper规则配置的入口,它只提供一个静态的方法,在程序第一次运行的时候调用该方法完成配置。

当有多个Profile的时候,我们可以这样添加:

public class Configuration
{public static void Configure(){Mapper.Initialize(cfg =>{cfg.AddProfile<Profiles.SourceProfile>();cfg.AddProfile<Profiles.OrderProfile>();cfg.AddProfile<Profiles.CalendarEventProfile>();});}
}

在程序运行的时候,只需要调用Configure方法即可。

了解了这些实现以后,我们可以再项目中添加AutoMapper文件夹,文件夹结构如下:

image

Configuration为我们的静态配置入口类;Profiles文件夹为我们所有Profile类的文件夹。如果是MVC,我们需要在Global中调用:

AutoMapper.Configuration.Configure();

扁平化映射(Flattening)

默认情况下,我们的Source类和Destination类是根据属性名称进行匹配映射的。除此之外,默认的映射规则还有下面两种情况,我们称之为扁平化映射,即当Source类中不包含Destination类中的属性的时候,AutoMapper会将Destination类中的属性进行分割,或匹配“Get”开头的方法,例如:

Order类:

public class Order
{public Customer Customer { get; set; }public decimal GetTotal(){return 100M;}
}

Order类中包含了一个customer对象和一个GetTotal方法,为了方便演示,我直接将GetTotal方法返回100;

Customer类的定义如下:

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

OrderDto类的定义如下:

public class OrderDto
{public string CustomerName { get; set; }public string Total { get; set; }
}

我们在进行映射的时候,不需要进行特殊的配置,既可以完成从Order到OrderDto的映射。

public class OrderProfile : Profile
{protected override void Configure(){CreateMap<Entity.Order, Dto.OrderDto>();}
}

测试代码:

Entity.Customer customer = new Entity.Customer() { Name = "Tom" };
Entity.Order order = new Entity.Order() { Customer = customer };
Dto.OrderDto orderDto = Mapper.Map<Dto.OrderDto>(order);
ObjectDumper.Write(order, 2);
ObjectDumper.Write(orderDto);

测试结果:

image

指定映射字段(Projection)

在实际的业务环境中,我们的Source类和Destination类的字段不可能一对一的匹配,这个时候我们就需要来指定他们的实际映射关系,例如:

public class CalendarEvent
{public DateTime Date { get; set; }public string Title { get; set; }
}public class CalendarEventForm
{public DateTime EventDate { get; set; }public int EventHour { get; set; }public int EventMinute { get; set; }public string DisplayTitle { get; set; }
}

在这两个类中,CalendarEvent的Date将被拆分为CalendarEventForm的日期、时、分三个字段,Title也将对应DisplayTitle字段,那么相应的Profile定义如下:

public class CalendarEventProfile : Profile
{protected override void Configure(){CreateMap<Entity.CalendarEvent, Entity.CalendarEventForm>().ForMember(dest => dest.EventDate, opt => opt.MapFrom(src => src.Date.Date)).ForMember(dest => dest.EventHour, opt => opt.MapFrom(src => src.Date.Hour)).ForMember(dest => dest.EventMinute, opt => opt.MapFrom(src => src.Date.Minute)).ForMember(dest => dest.DisplayTitle, opt => opt.MapFrom(src => src.Title));}
}

测试代码:

Entity.CalendarEvent calendarEvent = new Entity.CalendarEvent()
{Date = DateTime.Now,Title = "Demo Event"
};
Entity.CalendarEventForm calendarEventForm = Mapper.Map<Entity.CalendarEventForm>(calendarEvent);
ObjectDumper.Write(calendarEventForm);

测试结果:

image

验证配置项(Configuration Validation)

AutoMapper提供了一种验证机制,用来判断Destination类中的所有属性是否都被映射,如果存在未被映射的属性,则抛出异常。

验证的用法:

Mapper.AssertConfigurationIsValid();

例如:

public class Source
{public int SomeValue { get; set; }public string AnotherValue { get; set; }
}

Destination代码:

public class Destination
{public int SomeValuefff { get; set; }
}

测试:

Mapper.CreateMap<Entity.Source, Entity.Destination>();
Mapper.AssertConfigurationIsValid();

运行程序将会出现AutoMapperConfigurationException异常:

image

这是因为SomeValuefff在Source类中没有对应的字段造成的。

解决这种异常的方法有:

指定映射字段,例如:

Mapper.CreateMap<Entity.Source, Entity.Destination>().ForMember(dest => dest.SomeValuefff, opt =>{opt.MapFrom(src => src.SomeValue);});

或者使用Ignore方法:

Mapper.CreateMap<Entity.Source, Entity.Destination>().ForMember(dest => dest.SomeValuefff, opt =>{opt.Ignore();});

或者使用自定义解析器,自定义解析器在下面讲到。

自定义解析器(Custom value resolvers)

AutoMapper允许我们自定义解析器来完成Source到Destination的值的转换。例如:

public class Source
{public int Value1 { get; set; }public int Value2 { get; set; }
}public class Destination
{public int Total { get; set; }
}

Total属性在Source中不存在,如果现在创建映射规则,在映射的时候必然会抛出异常。这个时候我们就需要使用自定义解析器来完成映射。

自定义解析器需要实现 IValueResolver 接口,接口的定义如下:

public interface IValueResolver
{ResolutionResult Resolve(ResolutionResult source);
}

我们来自定义一个Resolver:

public class CustomResolver : ValueResolver<Source, int>
{protected override int ResolveCore(Source source){return source.Value1 + source.Value2;}
}

然后在映射规则中使用这个解析器:

public class SourceProfile : Profile
{protected override void Configure(){//Source->DestinationCreateMap<Source, Destination>().ForMember(dest => dest.Total, opt =>{opt.ResolveUsing<CustomResolver>();});}
}

测试代码:

Source src = new Source()
{Value1 = 1,Value2 = 2
};
Destination dest = Mapper.Map<Destination>(src);
ObjectDumper.Write(dest);

测试结果:

image

在使用自定义Resolver中,我们还可以指定Resolver的构造函数,例如:

//Source->Destination
CreateMap<Source, Destination>().ForMember(dest => dest.Total, opt =>{opt.ResolveUsing<CustomResolver>().ConstructedBy(() => 

new CustomResolver

());});

自定义类型转换器(Custom type converters)

AutoMapper通过ConvertUsing来使用自定义类型转换器。ConvertUsing有三种用法:

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

当我们有如下的Source类和Destination类:

public class Source
{public string Value1 { get; set; }
}public class Destination
{public int Value1 { get; set; }
}

我们可以使用如下配置:

public class SourceProfile : Profile
{protected override void Configure(){//string->intCreateMap<string, int>().ConvertUsing(Convert.ToInt32);//Source->DestinationCreateMap<Source, Destination>();}
}

在上面的配置中,我们首先创建了从string到int的类型转换,这里使用了系统自带的Convert.ToInt32转换方法。

除了这种方法之外,我们还可以自定义类型转换器:

public class CustomConverter : ITypeConverter<Source, Destination>
{public Destination Convert(ResolutionContext context){Source src = context.SourceValue as Source;Destination dest = new Destination();dest.Value1 = System.Convert.ToInt32(src.Value1);return dest;}
}

通过这个转换器,我们可以绕过string到int的转换,直接将Source类的对象转换为Destination类的对象。

对应的配置如下:

public class SourceProfile : Profile
{protected override void Configure(){//Source->DestinationCreateMap<Source, Destination>().ConvertUsing<CustomConverter>();}
}

或者,我们也可以使用下面的配置:

public class SourceProfile : Profile
{protected override void Configure(){//Source->DestinationCustomConverter converter = new CustomConverter();CreateMap<Source, Destination>().ConvertUsing(converter);}
}

空值替换(Null substitution)

空值替换允许我们将Source对象中的空值在转换为Destination的值的时候,使用指定的值来替换空值。

public class Source
{public string Value { get; set; }
}public class Destination
{public string Value { get; set; }
}

配置代码:

public class SourceProfile : Profile
{protected override void Configure(){//Source->DestinationCreateMap<Source, Destination>().ForMember(dest => dest.Value, opt =>{opt.NullSubstitute("原始值为NULL");});}
}

测试代码:

Source src = new Source();
Destination dest = Mapper.Map<Destination>(src);
ObjectDumper.Write(dest);

测试结果:

image

条件映射(Conditional mapping)

条件映射只当Source类中的属性值满足一定条件的时候才进行映射。例如:

public class Foo
{public int baz;
}public class Bar
{public uint baz;
}

对应的配置代码如下:

Mapper.CreateMap<Foo, Bar>().ForMember(dest => dest.baz, opt =>{opt.Condition(src => (src.baz >= 0));});

总结

AutoMapper的一些常用方法都已经整理出来,代码也都在文章中,不再提供下载。

作者:齐飞

原文:http://www.qeefee.com/article/automapper

转载于:https://www.cnblogs.com/hegx/p/6605426.html

相关文章:

【洛谷习题】小A点菜

虽然也是一道dp的入门题&#xff0c;但就是想不到&#xff0c;或者说不会实现。dp还是要多做题。 链接&#xff1a;https://www.luogu.org/problemnew/show/P1164 我们可以设dp[i][j]表示以考虑完第i件&#xff0c;恰好消费j元的方案数。那么dp[i][j]dp[i-1][j]dp[i-1][j-a[i]]…

加载服务器版本信息,传奇服务器端启动加载错误的解决方法

1、启动服务端M2报错的类型2、错误分类&#xff0c;思路理清3、文字总结以下常见现象传奇服务器端启动加载错误解决方法Exception] 物品数据库加载错误![Exception] 魔法数据库加载错误!!! 地图数据加载错误.Code -1 加载Guardlist.txt时出现错误.Code -1 加载MakeItem.txt时出…

股票移动平均线matlab,股票的移动平均线 (图文)

股票的移动平均线【泸指】股票的移动平均线移动平均线是个强大的工具&#xff0c;能够更清晰地展示一系列无规律的数值变化 (比如股市波动)。此外&#xff0c;泸指移动平均线还可别除任何周期性变化(正常的季节性温度变化)的影响&#xff0c;便于我们观察到真正的趋势变化。移动…

htcd816+android密码,HTC Desire 816刷机解锁教程

一、解锁前的准备&#xff1a;1.解锁将会丢失所有数据&#xff0c;请先做好备份&#xff0c;如电话本、短信、照片、应用程序。2.下载并安装驱动程序HTC Driver。3.注册HTC Dev帐号&#xff0c;为提交解锁码做好准备。4.下载并解压 “Desire 816 解锁工具”&#xff1a;5.手机关…

BZOJ1058 [ZJOI2007]报表统计 set

原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ1058.html 题目传送门 - BZOJ1058 题解 考虑用两个 multiset 分别维护两个答案。 一个直接按照权值维护&#xff0c;另一个维护一下相邻位置的差。 比较容易想到如何维护的吧&#xff0c;不多讲&#xff0c;看代码吧。 代码…

扫描服务器端口信息工具,服务器端口扫描工具

服务器端口扫描工具 内容精选换一换2.3.2 端口扫描Internet上的大部分服务都使用一种基于TCP/IP协议的客户机/服务器的模式。在这种模式下&#xff0c;服务器端在某个TCP或UDP(User Datagram Protocol&#xff0c;用户数据报协议)的端口处于侦听状态&#xff0c;等待客户端程序…

python-Django-01基础配置

参考资料地址 http://www.ziqiangxuetang.com/django/django-install.html 官方文档 一&#xff1a; 1先下载Django源码包&#xff0c;下载地址https://www.djangoproject.com/download/ 然后下载自己想安装的版本 Django 1.5.x 支持 Python 2.6.5 Python 2.7, Python 3.2 和 3…

linux进程 网络占用率,linux CPU SI软中断比较占用率比较大(网络解决方案)

https://my.oschina.net/323148/blog/724408irq 默认linux自动启动的&#xff0c;但是往往它自己控制不是很好(CPU SI经常某个CPU占用大)通常碰到大流量的&#xff0c;通常我们会把自动启动的irqblance关闭&#xff0c;然后手动指定一下IRQ进行优化&#xff1a;看CPU的 si利用率…

android设备未指定怎么办,APKpath未指定为模块“示例 – 示例”

退出Android工作室 。 用pipe理员权限启动它。这解决了Windows 7中的 Android Studio v0.1的问题。我有同样的问题&#xff0c;我没有select 2个文件&#xff0c;然后收到错误"ERROR: APK path is not specified for module"我刚刚重新启动Android Studio并重新打开该…

链表 -- 双向循环链表(线性表)

1&#xff0c;双向链表也叫双链表&#xff0c;是链表的一种&#xff0c;它的每个数据结点中都有两个指针&#xff0c;分别指向直接后继和直接前驱。所以&#xff0c;从双向链表中的任意一个结点开始&#xff0c;都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循…

开发脚本自动部署及监控

1.编写脚本自动部署反向代理、web、nfs&#xff1b; 要求&#xff1a; I、部署nginx反向代理三个web服务&#xff0c;调度算法使用加权轮询&#xff1b; #!/bin/shngxStatusps aux | grep -v grep |grep -c nginxfunction ngxProxyInstall() { if [ -e /usr/sbin/nginx ];the…

服务器日志显示乱码,CentosOS 6.5 服务器 控制台输出中文乱码,日志打印中文也乱码...

系统是Centos 6.5使用localeLANGen_US.UTF-8LC_CTYPE"en_US.UTF-8"LC_NUMERICzh_CN.UTF-8LC_TIME"en_US.UTF-8"LC_COLLATE"en_US.UTF-8"LC_MONETARYzh_CN.UTF-8LC_MESSAGES"en_US.UTF-8"LC_PAPERzh_CN.UTF-8LC_NAMEzh_CN.UTF-8LC_ADDR…

go linux 源码编译环境,Linux 源码安装 GO 环境

Go 安装1.4以上的版本出现的问题个人在安装 go1.9.2 的时候&#xff0c;一直 提醒的错误是&#xff1a;Building Go bootstrap tool.cmd/distERROR: Cannot find /root/go1.4/bin/go.Set $GOROOT_BOOTSTRAP to a working Go tree > Go 1.4.步骤如果之前已经安装过老版本的 G…

django html数据库连接,Django数据库连接的问题

多线程运行项目。有N个工作线程从DB中获取jobs&#xff0c;并把结果写回DB。项目运行一段时间后&#xff0c;发现数据库连接耗尽了&#xff0c;幸好内存大&#xff0c;然后一直往上调&#xff0c;最后连接数都上8000多。耗尽连接数的时候&#xff0c;postgresql会出现类似这样的…

Java Web之XML基础

有好几天没有更新博客了&#xff0c;前段时间因为要开学了&#xff0c;需要凑足学费才能继续在学校学习&#xff0c;耽误了几天&#xff0c;这两天需要补充前面需要学习的一些知识点了。今天就开始进入JavaWeb阶段吧&#xff0c;这段时间我们需要了解一些前端的知识&#xff0c…

ios NSLayoutConstraint

为了让我们的应用在不同尺寸的屏幕下都能 “正常”的表示&#xff0c;我们尽量不要把数据写死。大多数可视元素都是一个矩形区域&#xff0c;当然这个矩形区域有坐标的&#xff0c;我们有了这个区域坐标就能确定可视元素的现实位置了。但是iphone5和以前的屏幕不一样了&#xf…

分布式技术追踪 2017年第十二期

分布式系统实践 1. 深入Facebook图数据库系统&#xff08;TAO&#xff09;系列 http://dwz.cn/5zQEdo http://dwz.cn/5zQEBK http://dwz.cn/5zQEPV 摘要: TAO是Facebook 的分布式图数据库, 存储了Facebook所有的社交关系数据, TAO的QPS超过30亿, 作者曾经在Facebook做过TAO相关…

linux 统计日志数量总,shell统计日志中时间段内匹配的数量的方法

shell统计日志中时间段内匹配的数量的方法&#xff0c;有需要的朋友可以参考下。假设日志文件mtasvr.log格式如下&#xff1a;T:24583088(04:02:06)[root:Info] 6KqowLDLAgC93DFIKrENAA.41S2:from,to, queuedT:122428336(13:36:51)[root:Info] 6KqowLAbAAByYzJIZGsOAA.2W:from,…

商品评论html,商品评论列表.html

提交取 消new Vue({el: #app,data: {fullLoad:,dialogVisible:false,jsonData:{"id":"","type":"edit","list":[{"type":"grid","icon":"icon-grid-","columns":[{"…

autolayout autoresizing

WWDC 2012 Session笔记——202, 228, 232 AutoLayout(自动布局)入门 这是博主的WWDC2012笔记系列中的一篇&#xff0c;完整的笔记列表可以参看这里。如果您是首次来到本站&#xff0c;也许您会有兴趣通过RSS&#xff0c;或者通过页面左侧的邮件订阅的方式订阅本站。 AutoLayout…

MongoDB安装和MongoChef可视化管理工具的使用

MongoDBWindows 用户向导&#xff1a;https://docs.mongodb.com/manual/tutorial/install-mongodb-on-windows/注意&#xff1a;最后一步时&#xff0c;左下角的勾勾要去掉&#xff0c;mongodb compass是图形化管理界面&#xff0c;下载它需要很久很久&#xff0c;还有可能一直…

angular轮播图

还是直接上代码比较好 <!doctype html><html lang"en"><head> <meta charset"UTF-8" /> <title>Document</title> <link rel"stylesheet" type"text/css" href"css/animate.min.css"…

linux 脚本的作用,shell export 作用

shell与export命令用户登录到Linux系统后&#xff0c;系统将启动一个用户shell。在这个shell中&#xff0c;可以使用shell命令或声明变量&#xff0c;也可以创建并运行shell脚本程序。运行shell脚本程序时&#xff0c;系统将创建一个子shell。此时&#xff0c;系统中将有两个sh…

标签选择器用于修改html元素默认的样式,html – 为什么CSS选择器与 sign(直接子)覆盖默认样式?...

问题不是子组合器(>)&#xff0c;它是color属性&#xff0c;它是可继承的。虽然颜色属性的初始值因浏览器而异&#xff0c;但继承是常见的。这意味着元素的文本颜色从父代继承。您在代码中看到这一点。相反&#xff0c;border属性是不可继承的。请注意&#xff0c;与文字颜色…

[hdu1828] Picture

帅哥美女们大家好&#xff01; 今天本蒟蒻补一篇题解&#xff01; 线段树维护扫描线求矩形周长并。 扫描线的话&#xff0c;跟求面积类似&#xff0c;这道题可以只扫一次&#xff0c;也可以x&#xff0c;y两个方向分别扫一次。 题目传送门 1 #include<cstdio>2 #include&…

洛谷 P2126 Mzc家中的男家丁

题目背景 &#xff4d;&#xff5a;&#xff43;与&#xff44;&#xff4a;&#xff4e;的…还没有众人皆知&#xff0c;所以我们要来宣传一下。 题目描述 &#xff4d;&#xff5a;&#xff43;家很有钱&#xff08;开玩笑&#xff09;&#xff0c;他家有&#xff4e;个男家丁…

linux如何查看内存最大的几个文件,详解Linux如何查看当前占用CPU或内存最多的几个进程...

命令ps -aux | sort -k4nr | head -N命令详解&#xff1a;1、head&#xff1a;-N可以指定显示的行数&#xff0c;默认显示10行。2、ps&#xff1a;参数a指代all――所有的进程&#xff0c;u指代userid――执行该进程的用户id&#xff0c;x指代显示所有程序&#xff0c;不以终端…

ios 真机调试

步骤&#xff1a; 一、真机调试所需材料说明二、进入申请界面三、添加App ID四、添加设备(Devices)五、添加证书(Certificates)六、添加描述文件(Provisioning Profiles)七、配置XCode 一、真机调试所需材料说明 在申请真机调试证书之前&#xff0c;先对苹果真机调试所需的文件…

html 表单内容怎么获取不到,jquery中formdate一直获取不到对象中的[0]的值 包括本身也是一个空的数据怎么办?...

jquery中formdate一直获取不到对象中的[0]的值 包括本身也是一个空的数据怎么办&#xff1f;再做一个前台的ajax方法 查网上用formdate方法上传。可是进了接口之后一直在控制台获取不到formdate的值包括formdate[0]的值也一样 接口应该是没有问题 因为用传统的表单submit提交也…

看雪CTF 2016_第八题分析

用exeinfo查看发现是x64程序&#xff0c;所以用平常的OD调试器是调试不到的&#xff0c;需要用x64的调试器 我这里是用x64dbug 这个调试器来进行调试分析 经过一步一步调试&#xff0c;发现程序调用RtlMoveMemory 这个api来进行获取我们输入的注册码 Rax的内存地址即为我们输入…