EmitMapper自动映射工具
在实体与DTO之间,我们一般都需要进行映射。如果手动的来进行转换,实在是太麻烦。所以就产生了很多映射工具,比如AutoMapper,EmitMapper。而经过一些对比,EmitMapper比较快,接近于手工转换的速度。
EmitMapper使用非常简单,对于那种属性名一样的,直接使用默认映射即可。如:
ObjectsMapper<From,To> mapper = ObjectMapperManager.DefaultInstance.GetMapper<From,To>();
to = mapper.Map(from);
它就会自动的把From对象的值赋给To对象;
对于有一定规则的,可以使用一些扩展的方法,如:
通过使用ConvertUsing可以配置一些组合映射.比如这个字段可以是某两个字段拼接,或者其他一些计算.具体可以参见一些使用例子:
http://www.cnblogs.com/aaa6818162/archive/2012/06/21/2557879.html
http://www.cnblogs.com/wuhong/archive/2011/09/21/2184313.html
但是在使用的过程中,发现了一个问题,就是本身默认是如果属性名相同就直接映射,而使用ConvertUsing是可以自定义映射条件的.但是如果使用了ConvertUsing,那么你必需为里面每个字段都指定映射的条件.而其实真正想用的是,在实体与DTO之间,其实大部分字段的属性名称是相同的,对于这些字段,我们是想直接默认映射,而对于其他一些需要自定义映射的字段,来自定义映射规则.但实际上却达不到这种效果,一般人也不想去把每个字段的映射规则配置一下,如果这样,还不如手动写呢.
后来在网上找到了一个例子,可以使用FlatteringConfig这个自定义配置,这个类在EmitMapper的源码中是有的,但是不是在当前的解决方案下,而是在一个叫EMConfigurations的项目里.可以这样使用这个自定义配置.
public class User
{
public Guid Id { get; set; }
public Company Company { get; set; }
}
public class Company
{
public Guid Id { get; set; }
}
public class UserDTO
{
public Guid Id { get; set; }
public Guid CompanyId{ get; set; }
}
ObjectMapperManager.DefaultInstance.GetMapper<User, UserDTO>(
new FlatteringConfig()
);
var dto = mapper.Map(new User());
这样,它就会自动的给DTO中的CompanyId赋值,也会给Id赋值.不过有一个规则就是CompanyId的命名要有一定的规则,一定要是那个实体的名称再加上这个实体里面属性的名称.这样才能进行自动的映射.(不过这时,如果那个实体为null,那也有可能会报错,没有试过,后面有时间试一下).
在运行的过程中,发现了FlatteringConfig类的一个bug;这个类的原始代码如下:
public class FlatteringConfig : DefaultMapConfig
{
protected Func<string, string, bool> nestedMembersMatcher;
public FlatteringConfig()
{
nestedMembersMatcher = (m1, m2) => m1.StartsWith(m2);
}
public override IMappingOperation[] GetMappingOperations(Type from, Type to)
{
var destinationMembers = GetDestinationMemebers(to);
var sourceMembers = GetSourceMemebers(from);
var result = new List<IMappingOperation>();
foreach (var dest in destinationMembers)
{
var matchedChain = GetMatchedChain(dest.Name, sourceMembers).ToArray();
if (matchedChain == null || matchedChain.Length == 0)
{
continue;
}
result.Add(
new ReadWriteSimple
{
Source = new MemberDescriptor(matchedChain),
Destination = new MemberDescriptor(new[] { dest })
}
);
}
return result.ToArray();
}
public DefaultMapConfig MatchNestedMembers(Func<string, string, bool> nestedMembersMatcher)
{
this.nestedMembersMatcher = nestedMembersMatcher;
return this;
}
private List<MemberInfo> GetMatchedChain(string destName, List<MemberInfo> sourceMembers)
{
var matches = sourceMembers.Where(s => MatchMembers(destName, s.Name) || nestedMembersMatcher(destName, s.Name));
int len = 0;
MemberInfo match = null;
foreach (var m in matches)
{
if (m.Name.Length > len)
{
len = m.Name.Length;
match = m;
}
}
if (match == null)
{
return null;
}
var result = new List<MemberInfo> { match };
if (!MatchMembers(destName, match.Name))
{
result.AddRange(
GetMatchedChain(destName.Substring(match.Name.Length), GetDestinationMemebers(match))
);
}
return result;
}
private static List<MemberInfo> GetSourceMemebers(Type t)
{
return GetMemebers(t)
.Where(
m =>
m.MemberType == MemberTypes.Field ||
m.MemberType == MemberTypes.Property ||
m.MemberType == MemberTypes.Method
)
.ToList();
}
private static List<MemberInfo> GetDestinationMemebers(MemberInfo mi)
{
Type t;
if (mi.MemberType == MemberTypes.Field)
{
t = mi.DeclaringType.GetField(mi.Name).FieldType;
}
else
{
t = mi.DeclaringType.GetProperty(mi.Name).PropertyType;
}
return GetDestinationMemebers(t);
}
private static List<MemberInfo> GetDestinationMemebers(Type t)
{
return GetMemebers(t).Where(m => m.MemberType == MemberTypes.Field || m.MemberType == MemberTypes.Property).ToList();
}
private static List<MemberInfo> GetMemebers(Type t)
{
BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public;
return t.GetMembers(bindingFlags).ToList();
}
}
在GetMappingOperations方法中,修改了以下代码:(原代码中是一个判断在一起,改成分作两个判断)
var matchedChainSingle = GetMatchedChain(dest.Name, sourceMembers);
if (matchedChainSingle == null)
{
continue;
}
var matchedChain = matchedChainSingle.ToArray();
if (matchedChain.Length == 0)
{
continue;
}
参考资料:
http://emitmapper.codeplex.com/
http://stackoverflow.com/questions/9619265/emit-mapper-flattering-and-property-name-mismatch
http://emitmapper.codeplex.com/SourceControl/changeset/view/69894#1192663
http://emitmapper.codeplex.com/SourceControl/changeset/view/42128#691132
http://stackoverflow.com/questions/12542749/emitmapper-flattering-config-nullreferenceexception?rq=1
EmitMapper自动映射工具的更多相关文章
- AutoMapper 自动映射工具
先引用对应的DLL. 11.转换匿名对象 结合LINQ映射新的实体类. using System;using System.Collections.Generic;using System.Linq; ...
- 使用SpringDataJdbc的@Query注解实现自动映射结果集 ----- RowMapper接口
使用@Query注解的时候,常常需要写sql来映射非域类的实例,通常的做法就是 实现 RowMapper接口,然后new实例一个一个的设置值进去...为此.出世了自动映射工具类 注意事项:此抽象类只是 ...
- [转]p2p端口映射工具 dog-tunnel
[转]p2p端口映射工具 dog-tunnel http://www.oschina.net/p/dog-tunnel 狗洞是一个高速的 P2P 端口映射工具,同时支持Socks5代理. 0.5版后开 ...
- 代码自动生成工具MyGeneration之一(程序员必备工具)
代码自动生成工具MyGeneration之一(程序员必备工具) 转 分类: C#2008-08-06 18:12 16064人阅读 评论(12) 收藏 举报 工具数据库相关数据库stringbrows ...
- .NET的DTO映射工具AutoMapper
.NET的DTO映射工具AutoMapper 原文:https://github.com/AutoMapper/AutoMapper/wiki/Getting-started 参考:http://ww ...
- 反射+自定义注解---实现Excel数据列属性和JavaBean属性的自动映射
简单粗暴,直奔主题. 需求:通过自定义注解和反射技术,将Excel文件中的数据自动映射到pojo类中,最终返回一个List<pojo>集合? 今天我只是通过一位使用者的身份来给各位分享 ...
- Touch 方法&属性 映射工具
Touch 方法&属性 映射工具(0.5 版本) 标签 : github 线上后门与接口调试: 原先需要测试一个接口(如Dubbo.DAO), 或为线上留后门, 需要写大量的Web层(Api. ...
- AutoMapper自动映射
十年河东,十年河西,莫欺少年穷. 学无止境,精益求精. 不扯犊子,直接进入正题: AutoMapper自动映射常用于EF中,能很好的解决DTO和Model之间相互映射的问题.在未使用AutoMappe ...
- 常见Bean映射工具分析评测及Orika介绍
原地址:http://tech.dianwoda.com/2017/11/04/gao-xing-neng-te-xing-feng-fu-de-beanying-she-gong-ju-orika/ ...
随机推荐
- webpack中使用babel处理es6语法
index.js const arr = [ new Promise(()=>{}), new Promise(()=>{}) ]; arr.map(item => { consol ...
- math.random用法
Math.random():获取0~1随机数 Math.floor() method rounds a number DOWNWARDS to the nearest integer, and ret ...
- ThinkPHP5入门(三)----模型篇
一.操作数据库 1.数据库连接配置 数据库默认的相关配置在项目的application\database.php中已经定义好. 只需要在模块的数据库配置文件中配置好当前模块需要连接的数据库的配置参数即 ...
- Spring @Value 默认值
@Value(value = "${etl.maxthreadcount:3}") private long MaxThreadCount;
- PAT——1071. 小赌怡情
常言道“小赌怡情”.这是一个很简单的小游戏:首先由计算机给出第一个整数:然后玩家下注赌第二个整数将会比第一个数大还是小:玩家下注t个筹码后,计算机给出第二个数.若玩家猜对了,则系统奖励玩家t个筹码:否 ...
- 【luogu P2245 星际导航】 题解
题目链接:https://www.luogu.org/problemnew/show/P2245 = 货车运输 被逼着写过mst+lca 后来成了mst+树剖 #include <cstdio& ...
- C++11之std::future和std::promise
为什么C++11引入std::future和std::promise?C++11创建了线程以后,我们不能直接从thread.join()得到结果,必须定义一个变量,在线程执行时,对这个变量赋值,然后执 ...
- Ubuntu 编译出现 ISO C++ 2011 不支持的解决办法
问题 在编译时出现如下error: error:This file requires compiler and library support for the ISO C++ 2011 standar ...
- 关于iPad上模态显示视图中的UITextField,UITextView在输入完成后无法回收键盘的问题解决。
在iPad开发过程中遇到一个问题,UITextField 存在由UIModalPresentationFormSheet 弹出的带导航条的视图控制器中时,调用 resignFirstResponder ...
- 字符型设备驱动程序-first-printf以及点亮LED灯(三)
根据 字符型设备驱动程序-first-printf以及点亮LED灯(二) 学习 修改函数 中的printf 为 printk. #include <linux/module.h> /* ...