java automapper 使用_AutoMapper实际项目运用
AutoMapper是對象到對象的映射工具。在完成映射規(guī)則之后,AutoMapper可以將源對象轉(zhuǎn)換為目標(biāo)對象。
配置AutoMapper映射規(guī)則
AutoMapper是基于約定的,因此在實用映射之前,我們需要先進(jìn)行映射規(guī)則的配置。
public class Source
{
public int SomeValue { get; set; }
public string AnotherValue { get; set; }
}
public class Destination
{
public int SomeValue { get; set; }
}
在上面的代碼中,我們定義了兩個類,我們需要將Source類的對象映射到Destination類的對象上面。要完成這個操作,我們需要對AutoMapper進(jìn)行如下配置:
Mapper.CreateMap();
進(jìn)行一下測試:
Source src = new Source() { SomeValue = 1, AnotherValue = "2" };
Destination dest = Mapper.Map(src);
ObjectDumper.Write(dest);
我們可以在控制臺看到dest對象的屬性值:
這樣我們就完成了一個簡單的AutoMapper映射。
Profile的用法
Profile提供了一個命名的映射類,所有繼承自Profile類的子類都是一個映射集合。
我們來看一下Profile的用法,這個例子中仍然使用上面的Source類和Destination類。
public class SourceProfile : Profile
{
protected override void Configure()
{
CreateMap();
}
}
我們可以再Profile中重寫Configure方法,從而完成映射規(guī)則的配置。從Profile初始化Mapper規(guī)則:
Mapper.Initialize(x => x.AddProfile());
在一個Profile中,我們可以完成多個、更復(fù)雜的規(guī)則的約定:
public class Destination2
{
public int SomeValue { get; set; }
public string AnotherValue2 { get; set; }
}
public class SourceProfile : Profile
{
protected override void Configure()
{
//Source->Destination
CreateMap();
//Source->Destination2
CreateMap().ForMember(d => d.AnotherValue2, opt =>
{
opt.MapFrom(s => s.AnotherValue);
});
}
}
AutoMapper最佳實踐
這段內(nèi)容將討論AutoMapper的規(guī)則寫在什么地方的問題。
在上一段中,我們已經(jīng)知道了如何使用AutoMapper進(jìn)行簡單的對象映射,但是,在實際的項目中,我們會有很多類進(jìn)行映射(從Entity轉(zhuǎn)換為Dto,或者從Entity轉(zhuǎn)換為ViewModel等),這么多的映射如何組織將成為一個問題。
首先我們需要定義一個Configuration.cs的類,該類提供AutoMapper規(guī)則配置的入口,它只提供一個靜態(tài)的方法,在程序第一次運行的時候調(diào)用該方法完成配置。
當(dāng)有多個Profile的時候,我們可以這樣添加:
public class Configuration
{
public static void Configure()
{
Mapper.Initialize(cfg =>
{
cfg.AddProfile();
cfg.AddProfile();
cfg.AddProfile();
});
}
}
在程序運行的時候,只需要調(diào)用Configure方法即可。
了解了這些實現(xiàn)以后,我們可以再項目中添加AutoMapper文件夾,文件夾結(jié)構(gòu)如下:
Configuration為我們的靜態(tài)配置入口類;Profiles文件夾為我們所有Profile類的文件夾。如果是MVC,我們需要在Global中調(diào)用:
AutoMapper.Configuration.Configure();
扁平化映射(Flattening)
默認(rèn)情況下,我們的Source類和Destination類是根據(jù)屬性名稱進(jìn)行匹配映射的。除此之外,默認(rèn)的映射規(guī)則還有下面兩種情況,我們稱之為扁平化映射,即當(dāng)Source類中不包含Destination類中的屬性的時候,AutoMapper會將Destination類中的屬性進(jìn)行分割,或匹配“Get”開頭的方法,例如:
Order類:
public class Order
{
public Customer Customer { get; set; }
public decimal GetTotal()
{
return 100M;
}
}
Order類中包含了一個customer對象和一個GetTotal方法,為了方便演示,我直接將GetTotal方法返回100;
Customer類的定義如下:
public class Customer
{
public string Name { get; set; }
}
OrderDto類的定義如下:
public class OrderDto
{
public string CustomerName { get; set; }
public string Total { get; set; }
}
我們在進(jìn)行映射的時候,不需要進(jìn)行特殊的配置,既可以完成從Order到OrderDto的映射。
public class OrderProfile : Profile
{
protected override void Configure()
{
CreateMap();
}
}
測試代碼:
Entity.Customer customer = new Entity.Customer() { Name = "Tom" };
Entity.Order order = new Entity.Order() { Customer = customer };
Dto.OrderDto orderDto = Mapper.Map(order);
ObjectDumper.Write(order, 2);
ObjectDumper.Write(orderDto);
測試結(jié)果:
指定映射字段(Projection)
在實際的業(yè)務(wù)環(huán)境中,我們的Source類和Destination類的字段不可能一對一的匹配,這個時候我們就需要來指定他們的實際映射關(guān)系,例如:
public class CalendarEvent
{
public DateTime Date { get; set; }
public string Title { get; set; }
}
public class CalendarEventForm
{
public DateTime EventDate { get; set; }
public int EventHour { get; set; }
public int EventMinute { get; set; }
public string DisplayTitle { get; set; }
}
在這兩個類中,CalendarEvent的Date將被拆分為CalendarEventForm的日期、時、分三個字段,Title也將對應(yīng)DisplayTitle字段,那么相應(yīng)的Profile定義如下:
public class CalendarEventProfile : Profile
{
protected override void Configure()
{
CreateMap()
.ForMember(dest => dest.EventDate, opt => opt.MapFrom(src => src.Date.Date))
.ForMember(dest => dest.EventHour, opt => opt.MapFrom(src => src.Date.Hour))
.ForMember(dest => dest.EventMinute, opt => opt.MapFrom(src => src.Date.Minute))
.ForMember(dest => dest.DisplayTitle, opt => opt.MapFrom(src => src.Title));
}
}
測試代碼:
Entity.CalendarEvent calendarEvent = new Entity.CalendarEvent()
{
Date = DateTime.Now,
Title = "Demo Event"
};
Entity.CalendarEventForm calendarEventForm = Mapper.Map(calendarEvent);
ObjectDumper.Write(calendarEventForm);
測試結(jié)果:
驗證配置項(Configuration Validation)
AutoMapper提供了一種驗證機制,用來判斷Destination類中的所有屬性是否都被映射,如果存在未被映射的屬性,則拋出異常。
驗證的用法:
Mapper.AssertConfigurationIsValid();
例如:
public class Source
{
public int SomeValue { get; set; }
public string AnotherValue { get; set; }
}
Destination代碼:
public class Destination
{
public int SomeValuefff { get; set; }
}
測試:
Mapper.CreateMap();
Mapper.AssertConfigurationIsValid();
運行程序?qū)霈F(xiàn)AutoMapperConfigurationException異常:
這是因為SomeValuefff在Source類中沒有對應(yīng)的字段造成的。
解決這種異常的方法有:
指定映射字段,例如:
Mapper.CreateMap()
.ForMember(dest => dest.SomeValuefff, opt =>
{
opt.MapFrom(src => src.SomeValue);
});
或者使用Ignore方法:
Mapper.CreateMap()
.ForMember(dest => dest.SomeValuefff, opt =>
{
opt.Ignore();
});
或者使用自定義解析器,自定義解析器在下面講到。
自定義解析器(Custom value resolvers)
AutoMapper允許我們自定義解析器來完成Source到Destination的值的轉(zhuǎn)換。例如:
public class Source
{
public int Value1 { get; set; }
public int Value2 { get; set; }
}
public class Destination
{
public int Total { get; set; }
}
Total屬性在Source中不存在,如果現(xiàn)在創(chuàng)建映射規(guī)則,在映射的時候必然會拋出異常。這個時候我們就需要使用自定義解析器來完成映射。
自定義解析器需要實現(xiàn) IValueResolver 接口,接口的定義如下:
public interface IValueResolver
{
ResolutionResult Resolve(ResolutionResult source);
}
我們來自定義一個Resolver:
public class CustomResolver : ValueResolver
{
protected override int ResolveCore(Source source)
{
return source.Value1 + source.Value2;
}
}
然后在映射規(guī)則中使用這個解析器:
public class SourceProfile : Profile
{
protected override void Configure()
{
//Source->Destination
CreateMap()
.ForMember(dest => dest.Total, opt =>
{
opt.ResolveUsing();
});
}
}
測試代碼:
Source src = new Source()
{
Value1 = 1,
Value2 = 2
};
Destination dest = Mapper.Map(src);
ObjectDumper.Write(dest);
測試結(jié)果:
在使用自定義Resolver中,我們還可以指定Resolver的構(gòu)造函數(shù),例如:
//Source->Destination
CreateMap()
.ForMember(dest => dest.Total, opt =>
{
opt.ResolveUsing()
.ConstructedBy(() =>
new?CustomResolver
());
});
自定義類型轉(zhuǎn)換器(Custom type converters)
AutoMapper通過ConvertUsing來使用自定義類型轉(zhuǎn)換器。ConvertUsing有三種用法:
void ConvertUsing(Func mappingFunction);
void ConvertUsing(ITypeConverter converter);
void ConvertUsing() where TTypeConverter : ITypeConverter;
當(dāng)我們有如下的Source類和Destination類:
public class Source
{
public string Value1 { get; set; }
}
public class Destination
{
public int Value1 { get; set; }
}
我們可以使用如下配置:
public class SourceProfile : Profile
{
protected override void Configure()
{
//string->int
CreateMap()
.ConvertUsing(Convert.ToInt32);
//Source->Destination
CreateMap();
}
}
在上面的配置中,我們首先創(chuàng)建了從string到int的類型轉(zhuǎn)換,這里使用了系統(tǒng)自帶的Convert.ToInt32轉(zhuǎn)換方法。
除了這種方法之外,我們還可以自定義類型轉(zhuǎn)換器:
public class CustomConverter : ITypeConverter
{
public Destination Convert(ResolutionContext context)
{
Source src = context.SourceValue as Source;
Destination dest = new Destination();
dest.Value1 = System.Convert.ToInt32(src.Value1);
return dest;
}
}
通過這個轉(zhuǎn)換器,我們可以繞過string到int的轉(zhuǎn)換,直接將Source類的對象轉(zhuǎn)換為Destination類的對象。
對應(yīng)的配置如下:
public class SourceProfile : Profile
{
protected override void Configure()
{
//Source->Destination
CreateMap()
.ConvertUsing();
}
}
或者,我們也可以使用下面的配置:
public class SourceProfile : Profile
{
protected override void Configure()
{
//Source->Destination
CustomConverter converter = new CustomConverter();
CreateMap()
.ConvertUsing(converter);
}
}
空值替換(Null substitution)
空值替換允許我們將Source對象中的空值在轉(zhuǎn)換為Destination的值的時候,使用指定的值來替換空值。
public class Source
{
public string Value { get; set; }
}
public class Destination
{
public string Value { get; set; }
}
配置代碼:
public class SourceProfile : Profile
{
protected override void Configure()
{
//Source->Destination
CreateMap()
.ForMember(dest => dest.Value, opt =>
{
opt.NullSubstitute("原始值為NULL");
});
}
}
測試代碼:
Source src = new Source();
Destination dest = Mapper.Map(src);
ObjectDumper.Write(dest);
測試結(jié)果:
條件映射(Conditional mapping)
條件映射只當(dāng)Source類中的屬性值滿足一定條件的時候才進(jìn)行映射。例如:
public class Foo
{
public int baz;
}
public class Bar
{
public uint baz;
}
對應(yīng)的配置代碼如下:
Mapper.CreateMap()
.ForMember(dest => dest.baz, opt =>
{
opt.Condition(src => (src.baz >= 0));
});
總結(jié)
以上是生活随笔為你收集整理的java automapper 使用_AutoMapper实际项目运用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: nanomsg.nng 在windows
- 下一篇: 企业外贸海外邮箱服务哪个好?企业邮箱前缀