安装方式:使用vs自带的nuget管理工具,搜索AutoMapper ,选择第一个安装到你的项目即可。
我从网上找了一些资料,
参考网址:http://blog.csdn.net/csethcrm/article/details/52934325
下载了个demo,然后自己又写了一遍,我把AutoMapper 的使用分为两种:
1、viewmodel与实体的字段名字是一致的,viewmodel的字段可以与实体中的字段数量不一致。
还有一种情况是:源实体中的字段名字是Getxxx,那么viewmodel中对应的字段可以是xxx,也会自动对应赋值,比如我写的demo中源实体中GetA,viewmodel中的A;
再有一种情况就是实体中的实体赋值,在我写的这个例子中,源实体中包含的实体类字段为Sub,里面包含的字段名字为Age,
那么destmodel中对应的字段名字可以是:SubAge,那么automapper就可以自动为你赋值了,大家看最后的运行结果。
给大家看下我建的源实体:
public class Source1
{
public string Name { set; get; } public string GetA { set; get; }
public string GetD { set; get; } public string SetB { set; get; } public string c { set; get; } public SubSource1 Sub { set; get; }
} public class SubSource1
{
public string Age { set; get; }
}
还有viewmodel(要转化成为你想要的模型):
public class Dest1
{
public string Name { set; get; } public string A { set; get; } public string C { set; get; } public string SubAge { set; get; } public string D { set; get; }
}
我封装的扩展方法:
/// <summary>
/// 类型映射,默认字段名字一一对应
/// </summary>
/// <typeparam name="TDestination">转化之后的model,可以理解为viewmodel</typeparam>
/// <typeparam name="TSource">要被转化的实体,Entity</typeparam>
/// <param name="source">可以使用这个扩展方法的类型,任何引用类型</param>
/// <returns>转化之后的实体</returns>
public static TDestination MapTo<TDestination, TSource>(this TSource source)
where TDestination : class
where TSource : class
{
if (source == null) return default(TDestination);
var config = new MapperConfiguration(cfg => cfg.CreateMap<TSource, TDestination>());
var mapper = config.CreateMapper();
return mapper.Map<TDestination>(source);
}
使用方式:
var source1 = new Source1
{
Name = "source",
Sub = new SubSource1 { Age = "" },
c = "c",
GetA = "A",
SetB = "B"
}; var destViewModel = source1.MapTo<Source1,Dest1>();
运行结果:
2.viewmodel与实体字段名字没有全部对应,只有几个字段的名字和源实体中的字段名字是一样的,其他的字段是通过实体中的几个字段组合或者是格式或者是类型转化而来的,
使用方法:不能再使用这个扩展方法了,只能自己额外写代码,代码如下:
var config2 = new MapperConfiguration(
cfg => cfg.CreateMap<SourceUser, DestUser2>()
.ForMember(d => d.DestName, opt => opt.MapFrom(s => s.Name)) //指定字段一一对应
.ForMember(d => d.Birthday, opt => opt.MapFrom(src => src.Birthday.ToString("yy-MM-dd HH:mm")))//指定字段,并转化指定的格式
.ForMember(d => d.Age, opt => opt.Condition(src => src.Age > ))//条件赋值
.ForMember(d => d.A1, opt => opt.Ignore())//忽略该字段,不给该字段赋值
.ForMember(d => d.A1, opt => opt.NullSubstitute("Default Value"))//如果源字段值为空,则赋值为 Default Value
.ForMember(d => d.A1, opt => opt.MapFrom(src => src.Name + src.Age * + src.Birthday.ToString("d"))));//可以自己随意组合赋值
var mapper2 = config2.CreateMapper();
注释中都包含了平时常用的几种情况,其他的我就没有再写。
下面再给大家把list转化的扩展方法代码贴上:
/// <summary>
/// 集合列表类型映射,默认字段名字一一对应
/// </summary>
/// <typeparam name="TDestination">转化之后的model,可以理解为viewmodel</typeparam>
/// <typeparam name="TSource">要被转化的实体,Entity</typeparam>
/// <param name="source">可以使用这个扩展方法的类型,任何引用类型</param>
/// <returns>转化之后的实体列表</returns>
public static IEnumerable<TDestination> MapToList<TSource,TDestination>(this IEnumerable<TSource> source)
where TDestination : class
where TSource : class
{
if (source == null) return new List<TDestination>();
var config = new MapperConfiguration(cfg => cfg.CreateMap<TSource, TDestination>());
var mapper = config.CreateMapper();
return mapper.Map<List<TDestination>>(source);
}
同样的使用方式:
var source1 = new Source1
{
Name = "source",
Sub = new SubSource1 { Age = "" },
c = "c",
GetA = "A",
SetB = "B"
};
var source3 = new Source1
{
Name = "source3",
Sub = new SubSource1 { Age = "" },
c = "c3",
GetA = "A3",
SetB = "B3"
};
var sourceList = new List<Source1> { source1, source3 };
var destViewModelList = sourceList.MapToList<Source1,Dest1>();
运行结果:
以上就是我个人所得,如有错误,欢迎大家指正。
//2017.12.4 修改:destination和source写反了,导致我的总结有些错误,现在纠正一下:错误结论已经红色标注,中间的截图也换成正确的了,工具类方法也已经修正。
出处:https://www.cnblogs.com/dawenyang/p/7966850.html
===========================================================
一、最简单的用法
有两个类User和UserDto
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
} public class UserDto
{
public string Name { get; set; }
public int Age { get; set; }
}
将User转换成UserDto也和简单
Mapper.Initialize(x => x.CreateMap<User, UserDto>());
User user = new User()
{
Id = ,
Name = "caoyc",
Age =
};
var dto = Mapper.Map<UserDto>(user);
这是一种最简单的使用,AutoMapper会更加字段名称去自动对于,忽略大小写。
二、如果属性名称不同
将UserDto的Name属性改成Name2
Mapper.Initialize(x =>
x.CreateMap<User, UserDto>()
.ForMember(d =>d.Name2, opt => {
opt.MapFrom(s => s.Name);
})
); User user = new User()
{
Id = ,
Name = "caoyc",
Age =
}; var dto = Mapper.Map<UserDto>(user);
三、使用Profile配置
自定义一个UserProfile类继承Profile,并重写Configure方法
public class UserProfile : Profile
{
protected override void Configure()
{
CreateMap<User, UserDto>()
.ForMember(d => d.Name2, opt =>
{
opt.MapFrom(s => s.Name);
});
}
}
新版本的 autoMapper.UserProfile.Configure()”: 可能会有提示:没有找到适合的方法来重写 。
可以改为构造函数注入的方式
public class UserProfile : Profile
{
public UserProfile ()
{
CreateMap<User, UserDto>()
.ForMember(d => d.Name2, opt =>
{
opt.MapFrom(s => s.Name);
});
}
}
使用时就这样
Mapper.Initialize(x => x.AddProfile<UserProfile>()); User user = new User()
{
Id = ,
Name = "caoyc",
Age =
}; var dto = Mapper.Map<UserDto>(user);
四、空值替换NullSubstitute
空值替换允许我们将Source对象中的空值在转换为Destination的值的时候,使用指定的值来替换空值。
public class UserProfile : Profile
{
protected override void Configure()
{
CreateMap<User, UserDto>()
.ForMember(d => d.Name2, opt => opt.MapFrom(s => s.Name))
.ForMember(d => d.Name2, opt => opt.NullSubstitute("值为空")); }
}
Mapper.Initialize(x => x.AddProfile<UserProfile>()); User user = new User()
{
Id = ,
Age =
}; var dto = Mapper.Map<UserDto>(user);
结果为:
五、忽略属性Ignore
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
} public class UserDto
{
public string Name { get; set; }
public int Age { get; set; } } public class UserProfile : Profile
{
protected override void Configure()
{
CreateMap<User, UserDto>().ForMember("Name", opt => opt.Ignore());
}
}
使用
Mapper.Initialize(x => x.AddProfile<UserProfile>()); User user = new User()
{
Id = ,
Name="caoyc",
Age =
}; var dto = Mapper.Map<UserDto>(user);
结果:
六、预设值
如果目标属性多于源属性,可以进行预设值
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
} public class UserDto
{
public string Name { get; set; }
public int Age { get; set; }
public string Gender { get; set; } } public class UserProfile : Profile
{
protected override void Configure()
{
CreateMap<User, UserDto>();
}
}
使用
Mapper.Initialize(x => x.AddProfile<UserProfile>()); User user = new User()
{
Id = ,
Name="caoyc",
Age =
}; UserDto dto = new UserDto() {Gender = "男"};
Mapper.Map(user, dto);
七、类型转换ITypeConverter
如果数据中Gender存储的int类型,而DTO中Gender是String类型
public class User
{
public int Gender { get; set; }
} public class UserDto
{
public string Gender { get; set; }
}
类型转换类,需要实现接口ITypeConverter
public class GenderTypeConvertert : ITypeConverter<int, string>
{
public string Convert(int source, string destination, ResolutionContext context)
{
switch (source)
{
case :
destination = "男";
break;
case :
destination = "女";
break;
default:
destination = "未知";
break;
}
return destination;
}
}
配置规则
public class UserProfile : Profile
{
protected override void Configure()
{
CreateMap<User, UserDto>(); CreateMap<int, string>().ConvertUsing<GenderTypeConvertert>();
//也可以写这样
//CreateMap<int, string>().ConvertUsing(new GenderTypeConvertert());
}
}
使用
Mapper.Initialize(x => x.AddProfile<UserProfile>()); User user0 = new User() { Gender = };
User user1 = new User() { Gender = };
User user2 = new User() { Gender = };
var dto0= Mapper.Map<UserDto>(user0);
var dto1 = Mapper.Map<UserDto>(user1);
var dto2 = Mapper.Map<UserDto>(user2); Console.WriteLine("dto0:{0}", dto0.Gender);
Console.WriteLine("dto1:{0}", dto1.Gender);
Console.WriteLine("dto2:{0}", dto2.Gender);
结果
八、条件约束Condition
当满足条件时才进行映射字段,例如人类年龄,假设我们现在人类年龄范围为0-200岁(这只是假设),只有满足在这个条件才进行映射
DTO和Entity
public class User
{
public int Age { get; set; }
} public class UserDto
{
public int Age { get; set; }
}
Profile
public class UserProfile : Profile
{
protected override void Configure()
{
CreateMap<User, UserDto>().ForMember(dest=>dest.Age,opt=>opt.Condition(src=>src.Age>= && src.Age<=));
}
}
使用代码
Mapper.Initialize(x => x.AddProfile<UserProfile>()); User user0 = new User() { Age = };
User user1 = new User() { Age = };
User user2 = new User() { Age = };
var dto0= Mapper.Map<UserDto>(user0);
var dto1 = Mapper.Map<UserDto>(user1);
var dto2 = Mapper.Map<UserDto>(user2); Console.WriteLine("dto0:{0}", dto0.Age);
Console.WriteLine("dto1:{0}", dto1.Age);
Console.WriteLine("dto2:{0}", dto2.Age);
输出结果
出处:https://www.cnblogs.com/caoyc/p/6367828.html
===================================================
AutoMapper介绍
为什么要使用AutoMapper?
我们在实现两个实体之间的转换,首先想到的就是新的一个对象,这个实体的字段等于另一个实体的字段,这样确实能够实现两个实体之间的转换,但这种方式的扩展性,灵活性非常差,维护起来相当麻烦;实体之前转换的工具有很多,不过我还是决定使用AutoMapper,因为它足够轻量级,而且也非常流行,国外的大牛们都使用它使用AutoMapper可以很方便的实现实体和实体之间的转换,它是一个强大的对象映射工具。
一,如何添加AutoMapper到项目中?
在vs中使用打开工具 - 库程序包管理器 - 程序包管理控制平台,输入“Install-Package AutoMapper”命令,就可以把AutoMapper添加到项目中了〜
二,举个栗子
栗子1:两个实体之间的映射
Mapper.CreateMap <Test1,Test2>(); Test1 test1 = new Test1 {Id = 1,Name =“张三”,Date = DateTime.Now}; Test2 test2 = Mapper.Map <Test2>(test1);
栗子2:两个实体不同字段之间的映射
Mapper.CreateMap <Test1,Test2>()。ForMember(d => d.Name121,opt => opt.MapFrom(s => s.Name));
栗子3:泛型之间的映射
-
Mapper.CreateMap <Test1,Test2>();
-
var testList = Mapper.Map <List <Test1>,List <Test2 >>(testList);
三,扩展映射方法使映射变得更简单
-
using System.Collections;
-
using System.Collections.Generic;
-
using System.Data;
-
using AutoMapper;
-
namespace Infrastructure.Utility
-
-
{
-
/// <summary>
-
/// AutoMapper扩展帮助类
-
/// </summary>
-
public static class AutoMapperHelper
-
{
-
/// <summary>
-
/// 类型映射
-
/// </summary>
-
public static T MapTo<T>(this object obj)
-
{
-
if (obj == null) return default(T);
-
Mapper.CreateMap(obj.GetType(), typeof(T));
-
return Mapper.Map<T>(obj);
-
}
-
/// <summary>
-
/// 集合列表类型映射
-
/// </summary>
-
public static List<TDestination> MapToList<TDestination>(this IEnumerable source)
-
{
-
foreach (var first in source)
-
{
-
var type = first.GetType();
-
Mapper.CreateMap(type, typeof(TDestination));
-
break;
-
}
-
return Mapper.Map<List<TDestination>>(source);
-
}
-
/// <summary>
-
/// 集合列表类型映射
-
/// </summary>
-
public static List<TDestination> MapToList<TSource, TDestination>(this IEnumerable<TSource> source)
-
{
-
//IEnumerable<T> 类型需要创建元素的映射
-
Mapper.CreateMap<TSource, TDestination>();
-
return Mapper.Map<List<TDestination>>(source);
-
}
-
/// <summary>
-
/// 类型映射
-
/// </summary>
-
public static TDestination MapTo<TSource, TDestination>(this TSource source, TDestination destination)
-
where TSource : class
-
where TDestination : class
-
{
-
if (source == null) return destination;
-
Mapper.CreateMap<TSource, TDestination>();
-
return Mapper.Map(source, destination);
-
}
-
/// <summary>
-
/// DataReader映射
-
/// </summary>
-
public static IEnumerable<T> DataReaderMapTo<T>(this IDataReader reader)
-
{
-
Mapper.Reset();
-
Mapper.CreateMap<IDataReader, IEnumerable<T>>();
-
return Mapper.Map<IDataReader, IEnumerable<T>>(reader);
-
}
-
}
-
}
这样的话,你就可以这样使用了
var testDto = test.MapTo <Test2>();
var testDtoList = testList.MapTo <Test2>();
出处:https://blog.csdn.net/qq_35193189/article/details/80805451
=========================================================
构造函数映射:
Automapper – 如何映射到构造函数参数,而不是属性设置
我是使用的AutoMapper的版本是9.0
使用ConstructUsing
这将允许您指定在映射期间使用的构造函数。但是所有其他属性将根据约定自动映射。
注意,这不同于ConvertUsing,因为convert使用将不会继续通过约定映射,它会让你完全控制映射。
Mapper.CreateMap<ObjectFrom, ObjectTo>()
.ConstructUsing(x => new ObjectTo(x.arg0, x.arg1, x.etc));
具体使用,参考如下代码:
namespace AutoMapperTest
{
class Program
{
static void Main(string[] args)
{
var config = new MapperConfiguration(cif => cif.AddProfile <UserProfile>()); //方式一
//var config = new MapperConfiguration(cif => cif.AddProfile(new UserProfile()));//方式二
var mapper = config.CreateMapper(); var f = new ObjectFrom { TestName = "aaa", TestAge = , TestSex = "m" };
Console.WriteLine(JsonConvert.SerializeObject(f) + Environment.NewLine); var t = mapper.Map<ObjectTo>(f);
Console.WriteLine(JsonConvert.SerializeObject(t) + Environment.NewLine); Console.ReadKey();
}
} public class ObjectFrom
{
public string TestName { get; set; }
public int TestAge { get; set; }
public string TestSex { get; set; }
} public class ObjectTo
{
public ObjectTo(string name)
{
if (name == null)
{
throw new InvalidDataException("name cannot be null");
}
else
{
this._name = name;
}
} private readonly string _name;
public string Name { get { return _name; } }
public int Age { get; set; }
public string Gender { get; set; } } }
参考出处:http://www.voidcn.com/article/p-swatacoc-bsk.html
=========================================================
根据上面的理解和站在巨人的肩膀上,自己重新封装一次,用到项目中。
public static class AutoMapHelper
{ /// <summary>
/// 类型映射,默认字段名字一一对应
/// </summary>
/// <typeparam name="TDestination"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
public static TDestination AutoMapTo<TDestination>(this object obj)
{
if (obj == null) return default(TDestination);
var config = new AutoMapper.MapperConfiguration(cfg => cfg.CreateMap(obj.GetType(), typeof(TDestination)));
return config.CreateMapper().Map<TDestination>(obj);
} /// <summary>
/// 类型映射,可指定映射字段的配置信息
/// </summary>
/// <typeparam name="TSource">源数据:要被转化的实体对象</typeparam>
/// <typeparam name="TDestination">目标数据:转换后的实体对象</typeparam>
/// <param name="source">任何引用类型对象</param>
/// <param name="cfgExp">可为null,则自动一一映射</param>
/// <returns></returns>
public static TDestination AutoMapTo<TSource, TDestination>(this TSource source, Action<AutoMapper.IMapperConfigurationExpression> cfgExp)
where TDestination : class
where TSource : class
{
if (source == null) return default(TDestination);
var config = new AutoMapper.MapperConfiguration(cfgExp != null ? cfgExp : cfg => cfg.CreateMap<TSource, TDestination>());
var mapper = config.CreateMapper();
return mapper.Map<TDestination>(source);
} /// <summary>
/// 类型映射,默认字段名字一一对应
/// </summary>
/// <typeparam name="TSource">源数据:要被转化的实体对象</typeparam>
/// <typeparam name="TDestination">目标数据:转换后的实体对象</typeparam>
/// <param name="source">任何引用类型对象</param>
/// <returns>转化之后的实体</returns>
public static TDestination AutoMapTo<TSource, TDestination>(this TSource source)
where TDestination : class
where TSource : class
{
if (source == null) return default(TDestination);
var config = new AutoMapper.MapperConfiguration(cfg => cfg.CreateMap<TSource, TDestination>());
var mapper = config.CreateMapper();
return mapper.Map<TDestination>(source);
} /// <summary>
/// 集合列表类型映射,默认字段名字一一对应
/// </summary>
/// <typeparam name="TDestination">转化之后的实体对象,可以理解为viewmodel</typeparam>
/// <typeparam name="TSource">要被转化的实体对象,Entity</typeparam>
/// <param name="source">通过泛型指定的这个扩展方法的类型,理论任何引用类型</param>
/// <returns>转化之后的实体列表</returns>
public static IEnumerable<TDestination> AutoMapTo<TSource, TDestination>(this IEnumerable<TSource> source)
where TDestination : class
where TSource : class
{
if (source == null) return new List<TDestination>();
var config = new AutoMapper.MapperConfiguration(cfg => cfg.CreateMap<TSource, TDestination>());
var mapper = config.CreateMapper();
return mapper.Map<List<TDestination>>(source);
} }
其实还可以继续优化,在泛型中不需要知道指定source的类型了,因为可以直接获取到,后面有时间再调整吧。
c# AutoMapper 使用方式和再封装的更多相关文章
-
iOS开发之网络请求(基于AFNetworking的再封装)
最近一直很忙也没有什么时间写博客了.放假了休息一下,就写一篇博客来总结一下最近做项目中出现过的问题吧!!! 首先,在项目中我的起到了什么作用,无非就是把美工(UI设计师)给我们的图显示出来,然后再和服 ...
-
对Zlib单元进行再封装
对Zlib单元进行再封装 低版本DELPHI,如D7,ZLIB.pas单元封装的很简陋,因此有必要再封装,以增加使用的便利性. 高版本DELPHI,zlib.pas本身提供的接口已经相当完善. Zli ...
-
c# AutoMapper 使用方式
安装方式:使用vs自带的nuget管理工具,搜索AutoMapper ,选择第一个安装到你的项目即可. 我从网上找了一些资料,下载了个demo,然后自己又写了一遍,我把AutoMapper 的使用分为 ...
-
RecyclerView再封装
RecyclerView做为ListView的替代品,已经出了很久了,既然是替代品,那自然有些ListView没有的优点.比如说:可以随意切换list,grid,stagger.可以指定一个或多个it ...
-
lodash源码分析之缓存使用方式的进一步封装
在世界上所有的民族之中,支配着他们的喜怒选择的并不是天性,而是他们的观点. --卢梭<社会与契约论> 本文为读 lodash 源码的第九篇,后续文章会更新到这个仓库中,欢迎 star:po ...
-
struts2 中属性驱动(其实就是struts2 action 中处理 request 的参数【old 方式servlet api 封装数据到javabean中(or beanutils)】),这里属性驱动是新方式
1.属性驱动 a\ 一般的set public class UserAction extends ActionSupport { private String username; private S ...
-
mvc中使用Pagination,对其进行再封装
对其进行再次封装: (function($) { $["fn"]["easyPaging"] = function(o) { if (!o.pageSelect ...
-
Redisclient连接方式Hiredis简单封装使用,连接池、屏蔽连接细节
工作须要对Hiredis进行了简单封装,实现功能: 1.API进行统一,对外仅仅提供一个接口. 2.屏蔽上层应用对连接的细节处理: 3.底层採用队列的方式保持连接池,保存连接会话. 4.重连时採用时间 ...
-
封装类的方式访问数据库(封装字符串、json)
<?php class DBDA { public $host="localhost";//服务器地址 public $uid="root";//用户名 ...
随机推荐
-
Ubuntu 部署Postgresql
安装组件 客户端安装 sudo apt-get install postgresql-client 服务器安装 sudo apt-get install postgresql postgresql-c ...
-
深入JVM系列之(3):JavaCore和HeapDump
jvm 生成javacore和heapdump文件 在Server端开发与运维中,经常需要生成javacore和heapdump文件,以便分析jvm的运行状态.javacore文件中给出jvm线程的详 ...
-
Android 编程下的 Secret Code
我们很多人应该都做过这样的操作,打开拨号键盘输入 *#*#4636#*#* 等字符就会弹出一个界面显示手机相关的一些信息,这个功能在 Android 中被称为 Android Secret Code, ...
-
python_way day13 sqlalchemy
sqlalchemy 一对多 多对多 1.一对多 一.#创建表结构 class Host(Base): #所有的子类都继承这个基类 #创建表结构 __tablename__ = 'hosts' id ...
-
cocos2dx 内存管理机制
持续更新吧. 刚开始看了一些. 一,CCObject 提供引用计数 1,unsinged int m_uReference; //此为CCOBject的引用计数,初始化为 1: new CCObje ...
-
Android报错:WindowManager$BadTokenException: Unable to add window -- window has already been added
很久之前测试通过的代码,现在手机升级了Android7.0后一运行就崩溃,报出这样的错误,具体错误如下: Process: com.example.sho.android_anti_theft, PI ...
-
tomcat配置通过域名直接访问项目首页步骤
假设www.ctool.top.ip:192.168.122.135 step 1 申请一个域名并做好DNS解析,或者在hosts文件做域名指向 #vim /etc/hosts www.ctool.t ...
-
spring IOC中三种依赖注入方式
Spring的核心思想是IOC和AOP,IOC-控制反转,是一个重要的面向对象编程的法则,用来消减计算机程序之间的耦合问题,控制反转一般分为两种类型,依赖注入和依赖查找,依赖什么?为什么需要依赖?注入 ...
-
oracle 常用(一)
常用的6个分组函数: 注意点:where字句中不能使用组函数.要用到having函数. 但是从优化角度看,尽量使用where avg :平均值 sum:求和 ...
-
003-ubuntu上安装mysql
安装如下: 1.安装服务端:# sudo apt-get install mysql-server. 2.安装客户端:# sudo apt-get -y install mysql-server. ...