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 : 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

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

一、最簡單的用法

有兩個類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     }
復制代碼

 

新版本的 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);
復制代碼

 

四、空值替換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:泛型之間的映射

  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的類型了,因為可以直接獲取到,后面有時間再調整吧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM