c# AutoMapper 使用方式和再封装
安裝方式:使用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 : classwhere 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 = "25" },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 > 5))//條件賦值.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 * 3 + 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 : classwhere 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 = "25" },c = "c",GetA = "A",SetB = "B"};var source3 = new Source1{Name = "source3",Sub = new SubSource1 { Age = "253" },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
1 public class User 2 { 3 public int Id { get; set; } 4 public string Name { get; set; } 5 public int Age { get; set; } 6 } 7 8 public class UserDto 9 { 10 public string Name { get; set; } 11 public int Age { get; set; } 12 }將User轉換成UserDto也和簡單
1 Mapper.Initialize(x => x.CreateMap<User, UserDto>()); 2 User user = new User() 3 { 4 Id = 1, 5 Name = "caoyc", 6 Age = 20 7 }; 8 var dto = Mapper.Map<UserDto>(user);?這是一種最簡單的使用,AutoMapper會更加字段名稱去自動對于,忽略大小寫。
?
二、如果屬性名稱不同
將UserDto的Name屬性改成Name2
1 Mapper.Initialize(x => 2 x.CreateMap<User, UserDto>() 3 .ForMember(d =>d.Name2, opt => { 4 opt.MapFrom(s => s.Name); 5 }) 6 ); 7 8 User user = new User() 9 { 10 Id = 1, 11 Name = "caoyc", 12 Age = 20 13 }; 14 15 var dto = Mapper.Map<UserDto>(user);?
三、使用Profile配置
自定義一個UserProfile類繼承Profile,并重寫Configure方法
1 public class UserProfile : Profile 2 { 3 protected override void Configure() 4 { 5 CreateMap<User, UserDto>() 6 .ForMember(d => d.Name2, opt => 7 { 8 opt.MapFrom(s => s.Name); 9 }); 10 } 11 }使用時就這樣
1 Mapper.Initialize(x => x.AddProfile<UserProfile>()); 2 3 User user = new User() 4 { 5 Id = 1, 6 Name = "caoyc", 7 Age = 20 8 }; 9 10 var dto = Mapper.Map<UserDto>(user);?
四、空值替換NullSubstitute
空值替換允許我們將Source對象中的空值在轉換為Destination的值的時候,使用指定的值來替換空值。
1 public class UserProfile : Profile 2 { 3 protected override void Configure() 4 { 5 CreateMap<User, UserDto>() 6 .ForMember(d => d.Name2, opt => opt.MapFrom(s => s.Name)) 7 .ForMember(d => d.Name2, opt => opt.NullSubstitute("值為空")); 8 9 } 10 } 1 Mapper.Initialize(x => x.AddProfile<UserProfile>()); 2 3 User user = new User() 4 { 5 Id = 1, 6 Age = 20 7 }; 8 9 var dto = Mapper.Map<UserDto>(user);結果為:
?
五、忽略屬性Ignore
1 public class User 2 { 3 public int Id { get; set; } 4 public string Name { get; set; } 5 public int Age { get; set; } 6 } 7 8 public class UserDto 9 { 10 public string Name { get; set; } 11 public int Age { get; set; } 12 13 } 14 15 public class UserProfile : Profile 16 { 17 protected override void Configure() 18 { 19 CreateMap<User, UserDto>().ForMember("Name", opt => opt.Ignore()); 20 } 21 }使用
1 Mapper.Initialize(x => x.AddProfile<UserProfile>()); 2 3 User user = new User() 4 { 5 Id = 1, 6 Name="caoyc", 7 Age = 20 8 }; 9 10 var dto = Mapper.Map<UserDto>(user);結果:
?
六、預設值
如果目標屬性多于源屬性,可以進行預設值
1 public class User 2 { 3 public int Id { get; set; } 4 public string Name { get; set; } 5 public int Age { get; set; } 6 } 7 8 public class UserDto 9 { 10 public string Name { get; set; } 11 public int Age { get; set; } 12 public string Gender { get; set; } 13 14 } 15 16 public class UserProfile : Profile 17 { 18 protected override void Configure() 19 { 20 CreateMap<User, UserDto>(); 21 } 22 }使用
1 Mapper.Initialize(x => x.AddProfile<UserProfile>()); 2 3 User user = new User() 4 { 5 Id = 1, 6 Name="caoyc", 7 Age = 20 8 }; 9 10 UserDto dto = new UserDto() {Gender = "男"}; 11 Mapper.Map(user, dto);?七、類型轉換ITypeConverter
如果數據中Gender存儲的int類型,而DTO中Gender是String類型
1 public class User 2 { 3 public int Gender { get; set; } 4 } 5 6 public class UserDto 7 { 8 public string Gender { get; set; } 9 }類型轉換類,需要實現接口ITypeConverter
1 public class GenderTypeConvertert : ITypeConverter<int, string> 2 { 3 public string Convert(int source, string destination, ResolutionContext context) 4 { 5 switch (source) 6 { 7 case 0: 8 destination = "男"; 9 break; 10 case 1: 11 destination = "女"; 12 break; 13 default: 14 destination = "未知"; 15 break; 16 } 17 return destination; 18 } 19 }配置規則
1 public class UserProfile : Profile 2 { 3 protected override void Configure() 4 { 5 CreateMap<User, UserDto>(); 6 7 CreateMap<int, string>().ConvertUsing<GenderTypeConvertert>(); 8 //也可以寫這樣 9 //CreateMap<int, string>().ConvertUsing(new GenderTypeConvertert()); 10 } 11 }使用
1 Mapper.Initialize(x => x.AddProfile<UserProfile>()); 2 3 User user0 = new User() { Gender = 0 }; 4 User user1 = new User() { Gender = 1 }; 5 User user2 = new User() { Gender = 2 }; 6 var dto0= Mapper.Map<UserDto>(user0); 7 var dto1 = Mapper.Map<UserDto>(user1); 8 var dto2 = Mapper.Map<UserDto>(user2); 9 10 Console.WriteLine("dto0:{0}", dto0.Gender); 11 Console.WriteLine("dto1:{0}", dto1.Gender); 12 Console.WriteLine("dto2:{0}", dto2.Gender);結果
?
八、條件約束Condition
當滿足條件時才進行映射字段,例如人類年齡,假設我們現在人類年齡范圍為0-200歲(這只是假設),只有滿足在這個條件才進行映射
DTO和Entity
1 public class User 2 { 3 public int Age { get; set; } 4 } 5 6 public class UserDto 7 { 8 public int Age { get; set; } 9 }Profile
1 public class UserProfile : Profile 2 { 3 protected override void Configure() 4 { 5 CreateMap<User, UserDto>().ForMember(dest=>dest.Age,opt=>opt.Condition(src=>src.Age>=0 && src.Age<=200)); 6 } 7 }使用代碼
1 Mapper.Initialize(x => x.AddProfile<UserProfile>()); 2 3 User user0 = new User() { Age = 1 }; 4 User user1 = new User() { Age = 150 }; 5 User user2 = new User() { Age = 201 }; 6 var dto0= Mapper.Map<UserDto>(user0); 7 var dto1 = Mapper.Map<UserDto>(user1); 8 var dto2 = Mapper.Map<UserDto>(user2); 9 10 Console.WriteLine("dto0:{0}", dto0.Age); 11 Console.WriteLine("dto1:{0}", dto1.Age); 12 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:泛型之間的映射
三,擴展映射方法使映射變得更簡單
?
這樣的話,你就可以這樣使用了
? ? var testDto = test.MapTo <Test2>();?
? ? var testDtoList = testList.MapTo <Test2>();
?
?
?
出處:https://blog.csdn.net/qq_35193189/article/details/80805451
=========================================================
根據上面的理解和站在巨人的肩膀上,自己重新封裝一次,用到項目中。
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 : classwhere 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 : classwhere 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 : classwhere 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);}} View Code?其實還可以繼續優化,在泛型中不需要知道指定source的類型了,因為可以直接獲取到,后面有時間再調整吧。
轉載于:https://www.cnblogs.com/mq0036/p/10670202.html
總結
以上是生活随笔為你收集整理的c# AutoMapper 使用方式和再封装的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 0x13链表与邻接表之邻值查找
- 下一篇: eclipse自动补全