c# AutoMapper 使用方式和再封裝

安裝方式:使用vs自帶的nuget管理工具,搜索AutoMapper ,選擇第一個安裝到你的項目便可。php

我從網上找了一些資料,html

參考網址:http://blog.csdn.net/csethcrm/article/details/52934325app

下載了個demo,而後本身又寫了一遍,我把AutoMapper 的使用分爲兩種:ide

一、viewmodel與實體的字段名字是一致的,viewmodel的字段能夠與實體中的字段數量不一致。 函數

還有一種狀況是:源實體中的字段名字是Getxxx,那麼viewmodel中對應的字段能夠是xxx,也會自動對應賦值,好比我寫的demo中源實體中GetA,viewmodel中的A;工具

再有一種狀況就是實體中的實體賦值,在我寫的這個例子中,源實體中包含的實體類字段爲Sub,裏面包含的字段名字爲Age,post

那麼destmodel中對應的字段名字能夠是:SubAge,那麼automapper就能夠自動爲你賦值了,你們看最後的運行結果。優化

給你們看下我建的源實體:this

複製代碼
    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(要轉化成爲你想要的模型):spa

複製代碼
    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 = "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 : 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 = "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

===========================================================

1、最簡單的用法

有兩個類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會更加字段名稱去自動對於,忽略大小寫。

 

2、若是屬性名稱不一樣

將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);
複製代碼

 

3、使用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     }
複製代碼

 

新版本的 autoMapper.UserProfile.Configure()」: 可能會有提示:沒有找到適合的方法來重寫 。

能夠改成構造函數注入的方式

    public class UserProfile : Profile
    {
        public UserProfile ()
        {
            CreateMap<User, UserDto>()
                .ForMember(d => d.Name2, opt =>
                {
                    opt.MapFrom(s => s.Name);
                });
        }
    }

 

使用時就這樣

複製代碼
 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);
複製代碼

 

4、空值替換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);
複製代碼

結果爲:

 

5、忽略屬性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);
複製代碼

結果:

 

6、預設值

若是目標屬性多於源屬性,能夠進行預設值

複製代碼
 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);
複製代碼

 7、類型轉換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);
複製代碼

結果

 

8、條件約束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:泛型之間的映射

  1.  
      Mapper.CreateMap <Test1,Test2>(); 
  2.  
                var testList = Mapper.Map <List <Test1>,List <Test2 >>(testList);

三,擴展映射方法使映射變得更簡單

 

  1.  
    using System.Collections;
  2.  
    using System.Collections.Generic;
  3.  
    using System.Data;
  4.  
    using AutoMapper;
  5.  
    namespace Infrastructure.Utility
  6.  
     
  7.  
    {
  8.  
    /// <summary>
  9.  
    /// AutoMapper擴展幫助類
  10.  
    /// </summary>
  11.  
    public static class AutoMapperHelper
  12.  
    {
  13.  
    /// <summary>
  14.  
    /// 類型映射
  15.  
    /// </summary>
  16.  
    public static T MapTo<T>( this object obj)
  17.  
    {
  18.  
    if (obj == null) return default(T);
  19.  
    Mapper.CreateMap(obj.GetType(), typeof(T));
  20.  
    return Mapper.Map<T>(obj);
  21.  
    }
  22.  
    /// <summary>
  23.  
    /// 集合列表類型映射
  24.  
    /// </summary>
  25.  
    public static List<TDestination> MapToList<TDestination>( this IEnumerable source)
  26.  
    {
  27.  
    foreach ( var first in source)
  28.  
    {
  29.  
    var type = first.GetType();
  30.  
    Mapper.CreateMap(type, typeof(TDestination));
  31.  
    break;
  32.  
    }
  33.  
    return Mapper.Map<List<TDestination>>(source);
  34.  
    }
  35.  
    /// <summary>
  36.  
    /// 集合列表類型映射
  37.  
    /// </summary>
  38.  
    public static List<TDestination> MapToList<TSource, TDestination>( this IEnumerable<TSource> source)
  39.  
    {
  40.  
    //IEnumerable<T> 類型須要建立元素的映射
  41.  
    Mapper.CreateMap<TSource, TDestination>();
  42.  
    return Mapper.Map<List<TDestination>>(source);
  43.  
    }
  44.  
    /// <summary>
  45.  
    /// 類型映射
  46.  
    /// </summary>
  47.  
    public static TDestination MapTo<TSource, TDestination>( this TSource source, TDestination destination)
  48.  
    where TSource : class
  49.  
    where TDestination : class
  50.  
    {
  51.  
    if (source == null) return destination;
  52.  
    Mapper.CreateMap<TSource, TDestination>();
  53.  
    return Mapper.Map(source, destination);
  54.  
    }
  55.  
    /// <summary>
  56.  
    /// DataReader映射
  57.  
    /// </summary>
  58.  
    public static IEnumerable<T> DataReaderMapTo<T>( this IDataReader reader)
  59.  
    {
  60.  
    Mapper.Reset();
  61.  
    Mapper.CreateMap<IDataReader, IEnumerable<T>>();
  62.  
    return Mapper.Map<IDataReader, IEnumerable<T>>(reader);
  63.  
    }
  64.  
    }
  65.  
    }

這樣的話,你就能夠這樣使用了

    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 = 12, 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);
        }



    }
View Code

 其實還能夠繼續優化,在泛型中不須要知道指定source的類型了,由於能夠直接獲取到,後面有時間再調整吧。

相關文章
相關標籤/搜索