• AutoMapper 使用总结1


    初识AutoMapper

    在开始本篇文章之前,先来思考一个问题:一个项目分多层架构,如显示层、业务逻辑层、服务层、数据访问层。层与层访问需要数据载体,也就是类。如果多层通用一个类,一则会暴露出每层的字段,二者会使类字段很多,而且会出现很多冗余字段,这种方式是不可取的;如果每层都使用不同的类,则层与层调用时,一个字段一个字段的赋值又会很麻烦。针对第二种情况,可以使用AutoMapper来帮助我们实现类字段的赋值及转换。

    AutoMapper是一个对象映射器,它可以将一个一种类型的对象转换为另一种类型的对象。AutoMapper提供了映射规则及操作方法,使我们不用过多配置就可以映射两个类。

    安装AutoMapper

    通过Nuget安装AutoMapper,本次使用版本为6.2.2。

    AutoMapper配置

    初始化

    先创建两个类用于映射:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class ProductEntity
    {
        public string Name { getset; }
        public decimal Amount { getset; }
    }
     
    public class ProductDTO
    {
        public string Name { getset; }
        public decimal Amount { getset; }
    }

    Automapper可以使用静态类和实例方法来创建映射,下面分别使用这两种方式来实现 ProductEntity -> ProductDTO的映射。

    • 使用静态方式
    1
    2
    Mapper.Initialize(cfg => cfg.CreateMap<ProductEntity, ProductDTO>());
    var productDTO = Mapper.Map<ProductDTO>(productEntity);
    • 使用实例方法
    1
    2
    3
    MapperConfiguration configuration = new MapperConfiguration(cfg => cfg.CreateMap<ProductEntity, ProductDTO>());
    var mapper = configuration.CreateMapper();
    var productDTO = mapper.Map<ProductDTO>(productEntity);

    完整的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    [TestMethod]
    public void TestInitialization()
    {
        var productEntity = new ProductEntity()
        {
            Name = "Product" + DateTime.Now.Ticks,
            Amount = 10
        };
     
        Mapper.Initialize(cfg => cfg.CreateMap<ProductEntity, ProductDTO>());
        var productDTO = Mapper.Map<ProductDTO>(productEntity);
     
        Assert.IsNotNull(productDTO);
        Assert.IsNotNull(productDTO.Name);
        Assert.IsTrue(productDTO.Amount > 0);
    }

    Profiles设置

    除了使用以上两总方式类配置映射关系,也可以使用Profie配置来实现映射关系。

    创建自定义的Profile需要继承Profile类:

    1
    2
    3
    4
    5
    6
    7
    8
    public class MyProfile : Profile
    {
        public MyProfile()
        {
            CreateMap<ProductEntity, ProductDTO>();
            // Other mapping configurations
        }
    } 

    完成例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    [TestMethod]
    public void TestProfile()
    {
        var productEntity = new ProductEntity()
        {
            Name = "Product" + DateTime.Now.Ticks,
            Amount = 10
        };
         
        var configuration = new MapperConfiguration(cfg => cfg.AddProfile<MyProfile>());
        var productDTO = configuration.CreateMapper().Map<ProductDTO>(productEntity);
     
        Assert.IsNotNull(productDTO);
        Assert.IsNotNull(productDTO.Name);
        Assert.IsTrue(productDTO.Amount > 0);
    }

    除了使用AddProfile,也可以使用AddProfiles添加多个配置;同样,可以同时使用Mapper和Profile,也可以添加多个配置:

    1
    2
    3
    4
    5
    var configuration = new MapperConfiguration(cfg =>
    {
        cfg.AddProfile<MyProfile>();
        cfg.CreateMap<ProductEntity, ProductDTO>();
    });

    扁平化映射

    AutoMapper先映射名字一致的字段,如果没有,则会尝试使用以下规则来映射:

    • 目标中字段去掉前缀“Get”后的部分
    • 分割目标字段(根据Pascal命名方式)为单个单词

    先创建用到的映射类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class Product
    {
        public Supplier Supplier { getset; }
        public string Name { getset; }
     
        public decimal GetAmount()
        {
            return 10;
        }
    }
     
    public class Supplier
    {
        public string Name { getset; }
    }
     
    public class ProductDTO
    {
        public string SupplierName { getset; }
        public decimal Amount { getset; }
    }

    AutoMapper会自动实现Product.Supplier.Name -> ProductDTO.SupplierName, Product.GetTotal -> ProductDTO.Total的映射。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    [TestMethod]
    public void TestFalttening()
    {
        var supplier = new Supplier()
        {
            Name = "Supplier" + DateTime.Now.Ticks
        };
     
        var product = new Product()
        {
            Supplier = supplier,
            Name = "Product" + DateTime.Now.Ticks
        };
     
        Mapper.Initialize(cfg => cfg.CreateMap<Product, ProductDTO>());
     
        var productDTO = Mapper.Map<ProductDTO>(product);
     
        Assert.IsNotNull(productDTO);
        Assert.IsNotNull(productDTO.SupplierName);
        Assert.IsTrue(productDTO.Amount > 0);
    }

    集合验证

    AutoMapper除了可以映射单个对象外,也可以映射集合对象。AutoMapper源集合类型支持以下几种:

    • IEnumerable
    • IEnumerable<T>
    • ICollection
    • ICollection<T>
    • IList
    • IList<T>
    • List<T>
    • Arrays

    简单类型映射:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    public class Source
    {
        public int Value { getset; }
    }
     
    public class Destination
    {
        public int Value { getset; }
    }
     
    [TestMethod]
    public void TestCollectionSimple()
    {
        Mapper.Initialize(cfg => cfg.CreateMap<Source, Destination>());
     
        var sources = new[]
        {
            new Source {Value = 1},
            new Source {Value = 2},
            new Source {Value = 3}
        };
     
        IEnumerable<Destination> ienumerableDest = Mapper.Map<Source[], IEnumerable<Destination>>(sources);
        ICollection<Destination> icollectionDest = Mapper.Map<Source[], ICollection<Destination>>(sources);
        IList<Destination> ilistDest = Mapper.Map<Source[], IList<Destination>>(sources);
        List<Destination> listDest = Mapper.Map<Source[], List<Destination>>(sources);
        Destination[] arrayDest = Mapper.Map<Source[], Destination[]>(sources);
    }  

    复杂对象映射:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    public class Order
    {
        private IList<OrderLine> _lineItems = new List<OrderLine>();
     
        public OrderLine[] LineItems { get return _lineItems.ToArray(); } }
     
        public void AddLineItem(OrderLine orderLine)
        {
            _lineItems.Add(orderLine);
        }
    }
     
    public class OrderLine
    {
        public int Quantity { getset; }
    }
     
    public class OrderDTO
    {
        public OrderLineDTO[] LineItems { getset; }
    }
     
    public class OrderLineDTO
    {
        public int Quantity { getset; }
    }
     
    [TestMethod]
    public void TestCollectionNested()
    {
        Mapper.Initialize(cfg =>
        {
            cfg.CreateMap<Order, OrderDTO>();
            cfg.CreateMap<OrderLine, OrderLineDTO>();
        });
     
        var order = new Order();
        order.AddLineItem(new OrderLine {Quantity = 10});
        order.AddLineItem(new OrderLine {Quantity = 20});
        order.AddLineItem(new OrderLine {Quantity = 30});
     
        var orderDTO = Mapper.Map<OrderDTO>(order);
        Assert.IsNotNull(orderDTO);
        Assert.IsNotNull(orderDTO.LineItems);
        Assert.IsTrue(orderDTO.LineItems.Length > 0);
    }

    投影及条件映射

    投影(指定字段)

    除了以上使用的自动映射规则,AutoMapper还可以指定映射方式。下面使用ForMemeber指定字段的映射,将一个时间值拆分映射到日期、时、分:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    public class Calendar
    {
        public DateTime CalendarDate { getset; }
        public string Title { getset; }
    }
     
    public class CalendarModel
    {
        public DateTime Date { getset; }
        public int Hour { getset; }
        public int Minute { getset; }
        public string Title { getset; }
    }
     
    [TestMethod]
    public void TestProjection()
    {
        var calendar = new Calendar()
        {
            Title = "2018年日历",
            CalendarDate = new DateTime(2018, 1, 1, 11, 59, 59)
        };
     
        Mapper.Initialize(cfg => cfg
            .CreateMap<Calendar, CalendarModel>()
            .ForMember(dest => dest.Date, opt => opt.MapFrom(src =>src.CalendarDate.Date))
            .ForMember(dest => dest.Hour, opt => opt.MapFrom(src => src.CalendarDate.Hour))
            .ForMember(dest => dest.Minute, opt => opt.MapFrom(src => src.CalendarDate.Minute)));
     
        var calendarModel = Mapper.Map<CalendarModel>(calendar);
     
        Assert.AreEqual(calendarModel.Date.Ticks, new DateTime(2018, 1, 1).Ticks);
        Assert.AreEqual(calendarModel.Hour, 11);
        Assert.AreEqual(calendarModel.Minute, 59);
    }

    条件映射

     有些情况下,我们会考虑添加映射条件,比如,某个值不符合条件时,不允许映射。针对这种情况可以使用ForMember中的Condition:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    public class Source
    {
        public int Value { getset; }
    }
     
    public class Destination
    {
        public uint Value { getset; }
    }
     
     
    [TestMethod]
    public void TestConditionByCondition()
    {
        var source = new Source()
        {
            Value = 3
        };
     
        //如果Source.Value > 0, 则执行映射;否则,映射失败
        Mapper.Initialize(cfg => cfg
            .CreateMap<Source, Destination>()
            .ForMember(dest => dest.Value, opt => opt.Condition(src => src.Value > 0)));
     
        var destation = Mapper.Map<Destination>(source); //如果不符合条件,则抛出异常
     
        Assert.IsTrue(destation.Value.Equals(3));
    }

    如果要映射的类符合一定的规则,而且有很多,针对每个类都创建一个CreaterMapper会很麻烦。可以使用AddConditionalObjectMapper指定对象映射规则,这样就不用每个映射关系都添加一个CreateMapper。另外,也可以使用AddMemberConfiguration指定字段的映射规则,比如字段的前后缀:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    public class Product
    {
        public string Name { getset; }
        public int Count { getset; }
    }
     
    public class ProductModel
    {
        public string NameModel { getset; }
        public int CountMod { getset; }
    }
     
    [TestMethod]
    public void TestConditionByConfiguration()
    {
        var product = new Product()
        {
            Name = "Product" + DateTime.Now.Ticks,
            Count = 10
        };
     
        var config = new MapperConfiguration(cfg =>
        {
            //对象映射规则: 通过以下配置,可以映射所有”目标对象的名称“等于“源对象名称+Model”的类,而不用单个添加CreateMapper映射
            cfg.AddConditionalObjectMapper().Where((s, d) => d.Name == s.Name + "Model");
     
            //字段映射规则: 通过以下配置,可以映射“源字段”与“目标字段+Model或Mod”的字段
            cfg.AddMemberConfiguration().AddName<PrePostfixName>(_ => _.AddStrings(p => p.DestinationPostfixes, "Model""Mod"));
        });
     
        var mapper = config.CreateMapper();
     
        var productModel = mapper.Map<ProductModel>(product);
     
        Assert.IsTrue(productModel.CountMod == 10);
    }

    需要注意的一点是,添加了以上配置,如果目标对象中有字段没有映射到,则会抛出异常。

    值转换

    如果配置了值转换,AutoMapper会将修改转换后的值以符合配置的规则。比如,配置目标对象中的值添加符号“@@”:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    public class Source
    {
        public string Name { getset; }
    }
     
    public class Destination
    {
        public string Name { getset; }
    }
     
     
    [TestMethod]
    public void TestValueTransfer()
    {
        var source = new Source()
        {
            Name = "Bob"
        };
     
        Mapper.Initialize(cfg =>
        {
            cfg.CreateMap<Source, Destination>();
            cfg.ValueTransformers.Add<string>(val => string.Format("@{0}@", val));
        });
     
        var destation = Mapper.Map<Destination>(source);
     
        Assert.AreEqual("@Bob@", destation.Name);
    } 

    空值替换

    如果要映射的值为Null,则可以使用NullSubstitute指定Null值的替换值:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    public class Source
    {
        public string Name { getset; }
    }
     
    public class Destination
    {
        public string Name { getset; }
    }
     
     
    [TestMethod]
    public void TestValueTransfer()
    {
        var source = new Source()
        {
        };
     
        Mapper.Initialize(cfg =>
        {
            cfg.CreateMap<Source, Destination>()
            .ForMember(dest => dest.Name, opt => opt.NullSubstitute("其他值"));
        });
     
        var destation = Mapper.Map<Destination>(source);
     
        Assert.AreEqual("其他值", destation.Name);
    }

    配置验证及设置

    配置了映射,但是如何确定是否映射成功或者是否有字段没有映射呢?可以添加Mapper.AssertConfigurationIsValid();来验证是否映射成功。默认情况下,目标对象中的字段都被映射到后,AssertConfigurationIsValid才会返回True。也就是说,源对象必须包含所有目标对象,这样在大多数情况下不是我们想要的,我们可以使用下面的方法来指定验证规则:

    •  指定单个字段不验证
    •  指定整个Map验证规则
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    public class Product
    {
        public string Name { getset; }
        public int Amount { getset; }
    }
     
    public class ProductModel
    {
        public string Name { getset; }
        public int Amount { getset; }
        public string ViewName { getset; }
    }
     
    public class ProductDTO
    {
        public string Name { getset; }
        public int Amount { getset; }
        public string ViewName { getset; }
    }
     
    [TestMethod]
    public void TestValidation()
    {
        var product = new Product()
        {
            Name = "Product" + DateTime.Now.Ticks,
            Amount = 10
        };
     
        Mapper.Initialize(cfg =>
        {
            //1. 指定字段映射方式
            cfg.CreateMap<Product, ProductModel>()
                .ForMember(dest => dest.ViewName, opt => opt.Ignore()); //如果不添加此设置,会抛出异常
     
            //2. 指定整个对象映射方式
            //MemberList:
            //  Source: 检查源对象所有字段映射成功
            //  Destination:检查目标对象所有字段映射成功
            //  None: 跳过验证
            cfg.CreateMap<Product, ProductDTO>(MemberList.Source);
        });
     
        var productModel = Mapper.Map<ProductModel>(product);
        var productDTO = Mapper.Map<ProductDTO>(product);
     
        //验证映射是否成功
        Mapper.AssertConfigurationIsValid();
    }

    设置转换前后行为

    有的时候你可能会在创建映射前后对数据做一些处理,AutoMapper就提供了这种方式:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    public class Source
    {
        public string Name { getset; }
        public int Value { getset; }
    }
     
    public class Destination
    {
        public string Name { getset; }
        public int Value { getset; }
    }
     
    [TestMethod]
    public void TestBeforeOrAfter()
    {
        var source = new Source()
        {
            Name = "Product" + DateTime.Now.Ticks,
        };
     
        Mapper.Initialize(cfg =>
        {
            cfg.CreateMap<Source, Destination>()
                .BeforeMap((src, dest) => src.Value = src.Value + 10)
                .AfterMap((src, dest) => dest.Name = "Pobin");
        });
     
        var productModel = Mapper.Map<Destination>(source);
     
        Assert.AreEqual("Pobin", productModel.Name);
    }

    反向映射

    从6.1.0开始,AutoMapper通过调用Reverse可以实现反向映射。反向映射根据初始化时创建的正向映射规则来做反向映射:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    public class Order
    {
        public decimal Total { getset; }
        public Customer Customer { getset; }
    }
     
    public class Customer
    {
        public string Name { getset; }
    }
     
    public class OrderDTO
    {
        public decimal Total { getset; }
        public string CustomerName { getset; }
    }
     
    [TestMethod]
    public void TestReverseMapping()
    {
        var customer = new Customer
        {
            Name = "Tom"
        };
     
        var order = new Order
        {
            Customer = customer,
            Total = 20
        };
     
        Mapper.Initialize(cfg => {
            cfg.CreateMap<Order, OrderDTO>()
                .ForMember(dest => dest.CustomerName, opt => opt.MapFrom(src => src.Customer.Name)) //正向映射规则
                .ReverseMap(); //设置反向映射
        });
     
        //正向映射
        var orderDTO = Mapper.Map<OrderDTO>(order);
     
        //反向映射:使用ReverseMap,不用再创建OrderDTO -> Order的映射,而且还能保留正向的映射规则
        var orderConverted = Mapper.Map<Order>(orderDTO);
     
        Assert.IsNotNull(orderConverted.Customer);
        Assert.AreEqual("Tom", orderConverted.Customer.Name);
    }

    如果反向映射中不想使用原先的映射规则,也可以取消掉:

    1
    2
    3
    4
    5
    6
    Mapper.Initialize(cfg => {
        cfg.CreateMap<Order, OrderDTO>()
            .ForMember(dest => dest.CustomerName, opt => opt.MapFrom(src => src.Customer.Name)) //正向映射规则
            .ReverseMap()
            .ForPath(src => src.Customer.Name, opt => opt.Ignore()); //设置反向映射
    });

    自定义转换器

    有些情况下目标字段类型和源字段类型不一致,可以通过类型转换器实现映射,类型转换器有三种实现方式:

    1
    2
    3
    void ConvertUsing(Func<TSource, TDestination> mappingFunction);
    void ConvertUsing(ITypeConverter<TSource, TDestination> converter);
    void ConvertUsing<TTypeConverter>() where TTypeConverter : ITypeConverter<TSource, TDestination>;

    下面通过一个例子来演示下以上三种类型转换器的使用方式:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    namespace AutoMapperSummary
    {
        [TestClass]
        public class CustomerTypeConvert
        {
            public class Source
            {
                public string Value1 { getset; }
                public string Value2 { getset; }
                public string Value3 { getset; }
            }
     
            public class Destination
            {
                public int Value1 { getset; }
                public DateTime Value2 { getset; }
                public Type Value3 { getset; }
            }
     
            public class DateTimeTypeConverter : ITypeConverter<string, DateTime>
            {
                public DateTime Convert(string source, DateTime destination, ResolutionContext context)
                {
                    return System.Convert.ToDateTime(source);
                }
            }
     
            public class TypeTypeConverter : ITypeConverter<string, Type>
            {
                public Type Convert(string source, Type destination, ResolutionContext context)
                {
                    return Assembly.GetExecutingAssembly().GetType(source);
                }
            }
     
            [TestMethod]
            public void TestTypeConvert()
            {
                var config = new MapperConfiguration(cfg =>
                {
                    cfg.CreateMap<stringint>().ConvertUsing((string s) => Convert.ToInt32(s));
                    cfg.CreateMap<string, DateTime>().ConvertUsing(new DateTimeTypeConverter());
                    cfg.CreateMap<string, Type>().ConvertUsing<TypeTypeConverter>();
                    cfg.CreateMap<Source, Destination>();
                });
     
                config.AssertConfigurationIsValid(); //验证映射是否成功
     
                var source = new Source
                {
                    Value1 = "20",
                    Value2 = "2018/1/1",
                    Value3 = "AutoMapperSummary.CustomerTypeConvert+Destination"
                };
     
                var mapper = config.CreateMapper();
                var destination = mapper.Map<Source, Destination>(source);
     
                Assert.AreEqual(typeof(Destination), destination.Value3);
            }
        }
    }

    自定义解析器

    使用AutoMapper的自带解析规则,我们可以很方便的实现对象的映射。比如:源/目标字段名称一致,“Get/get + 源字段“与"目标字段"一致等。除了这些简单的映射,还可以使用ForMember指定字段映射。但是,某些情况下,解析规则会很复杂,使用自带的解析规则无法实现。这时可以自定义解析规则,可以通过以下三种方式使用自定义的解析器:

    1
    2
    3
    ResolveUsing<TValueResolver>
    ResolveUsing(typeof(CustomValueResolver))
    ResolveUsing(aValueResolverInstance)

    下面通过一个例子来演示如何使用自定义解析器:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    public class Source
    {
        public string FirstName { getset; }
        public string LastName { getset; }
    }
     
    public class Destination
    {
        public string Name { getset; }
    }
     
    /// <summary>
    /// 自定义解析器: 组合姓名
    /// </summary>
    public class CustomResolver : IValueResolver<Source, Destination, string>
    {
        public string Resolve(Source source, Destination destination, string destMember, ResolutionContext context)
        {
            if (source != null && !string.IsNullOrEmpty(source.FirstName) && !string.IsNullOrEmpty(source.LastName))
            {
                return string.Format("{0} {1}", source.FirstName, source.LastName);
            }
     
            return string.Empty;
        }
    }
     
    [TestMethod]
    public void TestResolver()
    {
        Mapper.Initialize(cfg =>
            cfg.CreateMap<Source, Destination>()
                .ForMember(dest => dest.Name, opt => opt.ResolveUsing<CustomResolver>()));
     
        Mapper.AssertConfigurationIsValid();
     
        var source = new Source
        {
            FirstName = "Michael",
            LastName = "Jackson"
        };
     
        var destination = Mapper.Map<Source, Destination>(source);
        Assert.AreEqual("Michael Jackson", destination.Name);
    }

    AutoMapper封装

    AutoMapper功能很强大,自定义配置支持也非常好,但是真正项目中使用时却很少用到这么多功能,而且一般都会对AutoMapper进一步封装使用。一方面使用起来方面,另外一方面也可以使代码统一。下面的只是做一个简单的封装,还需要结合实际项目使用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    /// <summary>
        /// AutoMapper帮助类
        /// </summary>
        public class AutoMapperManager
        {
            private static readonly MapperConfigurationExpression MapperConfiguration = new MapperConfigurationExpression();
     
            static AutoMapperManager()
            {
            }
     
            private AutoMapperManager()
            {
                AutoMapper.Mapper.Initialize(MapperConfiguration);
            }
     
            public static AutoMapperManager Instance { get; } = new AutoMapperManager();
     
            /// <summary>
            /// 添加映射关系
            /// </summary>
            /// <typeparam name="TSource"></typeparam>
            /// <typeparam name="TDestination"></typeparam>
            public void AddMap<TSource, TDestination>() where TSource : classnew() where TDestination : classnew()
            {
                MapperConfiguration.CreateMap<TSource, TDestination>();
            }
     
            /// <summary>
            /// 获取映射值
            /// </summary>
            /// <typeparam name="TDestination"></typeparam>
            /// <param name="source"></param>
            /// <returns></returns>
            public TDestination Map<TDestination>(object source) where TDestination : classnew()
            {
                if (source == null)
                {
                    return default(TDestination);
                }
     
                return Mapper.Map<TDestination>(source);
            }
     
            /// <summary>
            /// 获取集合映射值
            /// </summary>
            /// <typeparam name="TDestination"></typeparam>
            /// <param name="source"></param>
            /// <returns></returns>
            public IEnumerable<TDestination> Map<TDestination>(IEnumerable source) where TDestination : classnew()
            {
                if (source == null)
                {
                    return default(IEnumerable<TDestination>);
                }
     
                return Mapper.Map<IEnumerable<TDestination>>(source);
            }
     
            /// <summary>
            /// 获取映射值
            /// </summary>
            /// <typeparam name="TSource"></typeparam>
            /// <typeparam name="TDestination"></typeparam>
            /// <param name="source"></param>
            /// <returns></returns>
            public TDestination Map<TSource, TDestination>(TSource source) where TSource : classnew () where TDestination : classnew()
            {
                if (source == null)
                {
                    return default(TDestination);
                }
     
                return Mapper.Map<TSource, TDestination>(source);
            }
     
            /// <summary>
            /// 获取集合映射值
            /// </summary>
            /// <typeparam name="TSource"></typeparam>
            /// <typeparam name="TDestination"></typeparam>
            /// <param name="source"></param>
            /// <returns></returns>
            public IEnumerable<TDestination> Map<TSource, TDestination>(IEnumerable<TSource> source) where TSource : classnew() where TDestination : classnew()
            {
                if (source == null)
                {
                    return default(IEnumerable<TDestination>);
                }
     
                return Mapper.Map<IEnumerable<TSource>, IEnumerable<TDestination>>(source);
            }
     
            /// <summary>
            /// 读取DataReader内容
            /// </summary>
            /// <typeparam name="TDestination"></typeparam>
            /// <param name="reader"></param>
            /// <returns></returns>
            public IEnumerable<TDestination> Map<TDestination>(IDataReader reader)
            {
                if (reader == null)
                {
                    return new List<TDestination>();
                }
     
                var result = Mapper.Map<IEnumerable<TDestination>>(reader);
     
                if (!reader.IsClosed)
                {
                    reader.Close();
                }
                 
                return result;
            }
        }

    总结

    本篇文章列举了AutoMapper的基本使用方式,更多的使用可以参考官方文档:http://automapper.readthedocs.io/en/latest/index.html

  • 相关阅读:
    一篇就搞懂Mysql存储引擎和索引的文章
    ShardedJedisPipeline中sync()和syncAndReturnAll()区别
    17.win10安装Nginx及负载均衡配置,实现代理访问内网机器
    iDempiere 使用指南 系统安装 以及 virtualbox虚拟机下载
    程序员学数学【整理】
    element 表单校验
    draggable 拖拽列表排序(指定被拖拽的子元素)
    导出多个表的excel文件
    js自定义鼠标的图片
    table 导出简单的excel
  • 原文地址:https://www.cnblogs.com/dxqNet/p/9525383.html
Copyright © 2020-2023  润新知