java automapper 使用_AutoMapper用法(转载)

申明

作者:齐飞

配置AutoMapper映射规则

AutoMapper是基于约定的,因此在实用映射之前,我们需要先进行映射规则的配置。

1 public classSource2 {3 public int SomeValue { get; set; }4 public string AnotherValue { get; set; }5 }6

7 public classDestination8 {9 public int SomeValue { get; set; }10 }

在上面的代码中,我们定义了两个类,我们需要将Source类的对象映射到Destination类的对象上面。要完成这个操作,我们需要对AutoMapper进行如下配置:

1 Mapper.CreateMap();

进行一下测试:

1 Source src = new Source() { SomeValue = 1, AnotherValue = "2"};2 Destination dest = Mapper.Map(src);3 ObjectDumper.Write(dest);

我们可以在控制台看到dest对象的属性值:

3576dd4365aa8f83e563ea9e4919247b.png

这样我们就完成了一个简单的AutoMapper映射。

Profile的用法

Profile提供了一个命名的映射类,所有继承自Profile类的子类都是一个映射集合。

我们来看一下Profile的用法,这个例子中仍然使用上面的Source类和Destination类。

1 public classSourceProfile : Profile2 {3 protected override voidConfigure()4 {5 CreateMap();6 }7 }

我们可以再Profile中重写Configure方法,从而完成映射规则的配置。从Profile初始化Mapper规则:

1 Mapper.Initialize(x => x.AddProfile());

在一个Profile中,我们可以完成多个、更复杂的规则的约定:

1 public classDestination22 {3 public int SomeValue { get; set; }4 public string AnotherValue2 { get; set; }5 }6

7 public classSourceProfile : Profile8 {9 protected override voidConfigure()10 {11 //Source->Destination

12 CreateMap();13

14 //Source->Destination2

15 CreateMap().ForMember(d => d.AnotherValue2, opt =>

16 {17 opt.MapFrom(s =>s.AnotherValue);18 });19 }20 }

AutoMapper最佳实践

这段内容将讨论AutoMapper的规则写在什么地方的问题。

在上一段中,我们已经知道了如何使用AutoMapper进行简单的对象映射,但是,在实际的项目中,我们会有很多类进行映射(从Entity转换为Dto,或者从Entity转换为ViewModel等),这么多的映射如何组织将成为一个问题。

首先我们需要定义一个Configuration.cs的类,该类提供AutoMapper规则配置的入口,它只提供一个静态的方法,在程序第一次运行的时候调用该方法完成配置。

当有多个Profile的时候,我们可以这样添加:

1 public classConfiguration2 {3 public static voidConfigure()4 {5 Mapper.Initialize(cfg =>

6 {7 cfg.AddProfile();8 cfg.AddProfile();9 cfg.AddProfile();10 });11 }12 }

在程序运行的时候,只需要调用Configure方法即可。

了解了这些实现以后,我们可以再项目中添加AutoMapper文件夹,文件夹结构如下:

0bc2fa40ade433fcf5d5941a37fab275.png

Configuration为我们的静态配置入口类;Profiles文件夹为我们所有Profile类的文件夹。如果是MVC,我们需要在Global中调用:

1 AutoMapper.Configuration.Configure();

扁平化映射(Flattening)

默认情况下,我们的Source类和Destination类是根据属性名称进行匹配映射的。除此之外,默认的映射规则还有下面两种情况,我们称之为扁平化映射,即当Source类中不包含Destination类中的属性的时候,AutoMapper会将Destination类中的属性进行分割,或匹配“Get”开头的方法,例如:

Order类:

1 public classOrder2 {3 public Customer Customer { get; set; }4

5 public decimalGetTotal()6 {7 return100M;8 }9 }

Order类中包含了一个customer对象和一个GetTotal方法,为了方便演示,我直接将GetTotal方法返回100;

Customer类的定义如下:

1 public classCustomer2 {3 public string Name { get; set; }4 }

OrderDto类的定义如下:

1 public classOrderDto2 {3 public string CustomerName { get; set; }4 public string Total { get; set; }5 }

我们在进行映射的时候,不需要进行特殊的配置,既可以完成从Order到OrderDto的映射。

1 public classOrderProfile : Profile2 {3 protected override voidConfigure()4 {5 CreateMap();6 }7 }

测试代码:

1 Entity.Customer customer = new Entity.Customer() { Name = "Tom"};2 Entity.Order order = new Entity.Order() { Customer =customer };3 Dto.OrderDto orderDto = Mapper.Map(order);4 ObjectDumper.Write(order, 2);5 ObjectDumper.Write(orderDto);

测试结果:

486ff43d65351380a47a035cce32cbf4.png

指定映射字段(Projection)

在实际的业务环境中,我们的Source类和Destination类的字段不可能一对一的匹配,这个时候我们就需要来指定他们的实际映射关系,例如:

1 public classCalendarEvent2 {3 public DateTime Date { get; set; }4 public string Title { get; set; }5 }6

7 public classCalendarEventForm8 {9 public DateTime EventDate { get; set; }10 public int EventHour { get; set; }11 public int EventMinute { get; set; }12 public string DisplayTitle { get; set; }13 }

在这两个类中,CalendarEvent的Date将被拆分为CalendarEventForm的日期、时、分三个字段,Title也将对应DisplayTitle字段,那么相应的Profile定义如下:

1 public classCalendarEventProfile : Profile2 {3 protected override voidConfigure()4 {5 CreateMap()6 .ForMember(dest => dest.EventDate, opt => opt.MapFrom(src =>src.Date.Date))7 .ForMember(dest => dest.EventHour, opt => opt.MapFrom(src =>src.Date.Hour))8 .ForMember(dest => dest.EventMinute, opt => opt.MapFrom(src =>src.Date.Minute))9 .ForMember(dest => dest.DisplayTitle, opt => opt.MapFrom(src =>src.Title));10 }11 }

测试代码:

1 Entity.CalendarEvent calendarEvent = newEntity.CalendarEvent()2 {3 Date =DateTime.Now,4 Title = "Demo Event"

5 };6 Entity.CalendarEventForm calendarEventForm = Mapper.Map(calendarEvent);7 ObjectDumper.Write(calendarEventForm);

测试结果:

2dcb57817c6d6eb1a10b375b743e397d.png

验证配置项(Configuration Validation)

AutoMapper提供了一种验证机制,用来判断Destination类中的所有属性是否都被映射,如果存在未被映射的属性,则抛出异常。

验证的用法:

1 Mapper.AssertConfigurationIsValid();

例如:

1 public classSource2 {3 public int SomeValue { get; set; }4 public string AnotherValue { get; set; }5 }

Destination代码:

1 public classDestination2 {3 public int SomeValuefff { get; set; }4 }

测试:

1 Mapper.CreateMap();2 Mapper.AssertConfigurationIsValid();

运行程序将会出现AutoMapperConfigurationException异常:

1e01d8625a66484d93c60009906223ff.png

这是因为SomeValuefff在Source类中没有对应的字段造成的。

解决这种异常的方法有:

指定映射字段,例如:

1 Mapper.CreateMap()2 .ForMember(dest => dest.SomeValuefff, opt =>

3 {4 opt.MapFrom(src =>src.SomeValue);5 });

或者使用Ignore方法:

1 Mapper.CreateMap()2 .ForMember(dest => dest.SomeValuefff, opt =>

3 {4 opt.Ignore();5 });

或者使用自定义解析器,自定义解析器在下面讲到。

自定义解析器(Custom value resolvers)

AutoMapper允许我们自定义解析器来完成Source到Destination的值的转换。例如:

1 public classSource2 {3 public int Value1 { get; set; }4 public int Value2 { get; set; }5 }6

7 public classDestination8 {9 public int Total { get; set; }10 }

Total属性在Source中不存在,如果现在创建映射规则,在映射的时候必然会抛出异常。这个时候我们就需要使用自定义解析器来完成映射。

自定义解析器需要实现 IValueResolver 接口,接口的定义如下:

1 public interfaceIValueResolver2 {3 ResolutionResult Resolve(ResolutionResult source);4 }

我们来自定义一个Resolver:

1 public class CustomResolver : ValueResolver

2 {3 protected override intResolveCore(Source source)4 {5 return source.Value1 +source.Value2;6 }7 }

然后在映射规则中使用这个解析器:

1 public classSourceProfile : Profile2 {3 protected override voidConfigure()4 {5 //Source->Destination

6 CreateMap()7 .ForMember(dest => dest.Total, opt =>

8 {9 opt.ResolveUsing();10 });11 }12 }

测试代码:

1 Source src = newSource()2 {3 Value1 = 1,4 Value2 = 2

5 };6 Destination dest = Mapper.Map(src);7 ObjectDumper.Write(dest);

测试结果:

40c7f929d7a369efca2ced3a928752ab.png

在使用自定义Resolver中,我们还可以指定Resolver的构造函数,例如:

1 //Source->Destination

2 CreateMap()3 .ForMember(dest => dest.Total, opt =>

4 {5 opt.ResolveUsing()6 .ConstructedBy(() => newCustomResolver());7 });

自定义类型转换器(Custom type converters)

AutoMapper通过ConvertUsing来使用自定义类型转换器。ConvertUsing有三种用法:

1 void ConvertUsing(FuncmappingFunction);2 void ConvertUsing(ITypeConverterconverter);3 void ConvertUsing() where TTypeConverter : ITypeConverter;

当我们有如下的Source类和Destination类:

1 public classSource2 {3 public string Value1 { get; set; }4 }5

6 public classDestination7 {8 public int Value1 { get; set; }9 }

我们可以使用如下配置:

1 public classSourceProfile : Profile2 {3 protected override voidConfigure()4 {5 //string->int

6 CreateMap()7 .ConvertUsing(Convert.ToInt32);8 //Source->Destination

9 CreateMap();10 }11 }

在上面的配置中,我们首先创建了从string到int的类型转换,这里使用了系统自带的Convert.ToInt32转换方法。

除了这种方法之外,我们还可以自定义类型转换器:

1 public class CustomConverter : ITypeConverter

2 {3 publicDestination Convert(ResolutionContext context)4 {5 Source src = context.SourceValue asSource;6 Destination dest = newDestination();7 dest.Value1 =System.Convert.ToInt32(src.Value1);8

9 returndest;10 }11 }

通过这个转换器,我们可以绕过string到int的转换,直接将Source类的对象转换为Destination类的对象。

对应的配置如下:

1 public classSourceProfile : Profile2 {3 protected override voidConfigure()4 {5 //Source->Destination

6 CreateMap()7 .ConvertUsing();8 }9 }

或者,我们也可以使用下面的配置:

1 public classSourceProfile : Profile2 {3 protected override voidConfigure()4 {5 //Source->Destination

6 CustomConverter converter = newCustomConverter();7 CreateMap()8 .ConvertUsing(converter);9 }10 }

空值替换(Null substitution)

空值替换允许我们将Source对象中的空值在转换为Destination的值的时候,使用指定的值来替换空值。

1 public classSource2 {3 public string Value { get; set; }4 }5

6 public classDestination7 {8 public string Value { get; set; }9 }

配置代码:

1 public classSourceProfile : Profile2 {3 protected override voidConfigure()4 {5 //Source->Destination

6 CreateMap()7 .ForMember(dest => dest.Value, opt =>

8 {9 opt.NullSubstitute("原始值为NULL");10 });11 }12 }

测试代码:

1 Source src = newSource();2 Destination dest = Mapper.Map(src);3 ObjectDumper.Write(dest);

测试结果:

b22f09e6c2e14c80cdf2e378d757a68d.png

3c26da52b3e8500285000cf58c78323e.png

条件映射(Conditional mapping)

条件映射只当Source类中的属性值满足一定条件的时候才进行映射。例如:

1 public classFoo2 {3 public intbaz;4 }5

6 public classBar7 {8 public uintbaz;9 }

对应的配置代码如下:

1 Mapper.CreateMap()2 .ForMember(dest => dest.baz, opt =>

3 {4 opt.Condition(src => (src.baz >= 0));5 });

转载

作者:齐飞

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值