AutoMapper是基于对象到对象约定的映射工具,常用于(但并不仅限制于)把复杂的对象模型转为DTO,一般用于ViewModel模式和跨服务范畴。
AutoMapper给用户提供了便捷的配置API,就像使用约定来完成自动映射那样。AutoMapper包含以下功能:
通过分析几种场景,设立不同的层次的Model之间的Objectto object Map,例如Entity和PresentModel之间属性相差不多,通过automapper能够提高程序员的效率,至于应用的效率,有待商榷。
AutoMapper: A convention-based object-object mapper.
AutoMapper uses a convention-based matching algorithm tomatch up source to destination values. Currently, AutoMapper is geared towardsmodel projection scenarios to flatten complex object models to DTOs and othersimple objects, whose design is better suited for serialization, communication,messaging, or simply an anti-corruption layer between the domain andapplication layer.
以Convention方式实现零配置的对象映射
我们的AddressDto和Address结构完全一致,且字段名也完全相同。对于这样的类型转换,AutoMapper为我们提供了Convention,正如它的官网上所说的:
引用
AutoMapper uses a convention-basedmatching algorithm to match up source to destination values.
我们要做的只是将要映射的两个类型告诉AutoMapper(调用Mapper类的Static方法CreateMap并传入要映射的类型):
C#代码
Configuration定义类型间的简单映射规则
前面我们看了Convention的映射方式,客观的说还是有很多类型间的映射是无法通过简单的Convention方式来做的,这时候就需要我们使用Configuration了。好在我们的Configuration是在代码中以“强类型”的方式来写的,比写繁琐易错的xml方式是要好的多了。
先来看看BookDto到Publisher的映射。
回顾一下常用的对象Navigation然后ModelView中定义的规则:BookDto.Publisher-> Publisher.Name。
在AutoMapperzhong,我们可以这样映射:
C#代码
//通过一个最直观的Lambda表达式,把Source对象中找到的出版商名称对应到现实界面关联Model的Name属性。
var map = Mapper.CreateMap<BookDto,Publisher>();
map.ForMember(d => d.Name, opt => opt.MapFrom(s => s.Publisher));
AutoMapper使用ForMember来指定每一个字段的映射规则:
引用
The each custom member configuration uses an action delegateto configure each member.
还好有强大的lambda表达式,规则的定义简单明了。
在后台的项目中,使用了AutoMapper,
Presentation\Nop.Web\Administration\Infrastructure\AutoMapperStartupTask.cs
典型代码: //countries
Mapper.CreateMap<CountryModel, Country>()
.ForMember(dest =>dest.StateProvinces, mo => mo.Ignore())
.ForMember(dest =>dest.RestrictedShippingMethods, mo => mo.Ignore());
Mapper.CreateMap<Country, CountryModel>()
.ForMember(dest =>dest.NumberOfStates, mo => mo.MapFrom(src => src.StateProvinces != null ? src.StateProvinces.Count : 0))
.ForMember(dest =>dest.Locales, mo => mo.Ignore());
但是在电商前台,为了性能考虑,采用了属性Copy方式,可以看到Web项目没有引用AutoMapper。
Presentation\Nop.Web\Extensions\MappingExtensions.cs
public static AddressToEntity(this AddressModelmodel)
{
if(model == null)
return null;
varentity = new Address();
public static AddressModelToModel(this Addressentity)
{
if(entity == null)
returnnull;
varmodel = new AddressModel()
{
Id = entity.Id,
BugFix Progress:
var activityLogTypeModel =_customerActivityService.GetAllActivityTypes().Select(x => x.ToModel());
var gridModel = new GridModel<ActivityLogTypeModel>
Nop.Web\Administration\Controllers\ActivityLogController.cs
Nop.Web\Administration \MappingExtensions.cs\ ---All mapsare configured here:
Line 371:
//activity log
public static ActivityLogTypeModel ToModel(this ActivityLogTypeentity)
{
return Mapper.Map<ActivityLogType, ActivityLogTypeModel>(entity);
}
[AutoMapperMappingException: Trying to mapNop.Core.Domain.Logging.ActivityLogType toNop.Admin.Models.Logging.ActivityLogTypeModel.
Exception of type'AutoMapper.AutoMapperMappingException' was thrown.]
AutoMapper.MappingEngine.AutoMapper.IMappingEngineRunner.Map(ResolutionContextcontext) +318
AutoMapper.MappingEngine.Map(Object source,Type sourceType, Type destinationType) +72
AutoMapper.MappingEngine.Map(TSource source)+103
AutoMapper.Mapper.Map(TSource source) +69
Nop.Admin.MappingExtensions.ToModel(ActivityLogType entity) inC:\inetpub\wwwroot\nopcommerce\Presentation\Nop.Web\Administration\MappingExtensions.cs:369
?实现一个Mapping需要多少步骤?
另外一个相关的文件是\Presentation\Nop.Web\Administration\Infrastructure\AutoMapperStartupTask.cs,关于ActivityLogtype的,有些特别:
//ActivityLogType
Mapper.CreateMap<ActivityLogTypeModel,ActivityLogType>()
.ForMember(dest => dest.SystemKeyword, mo => mo.Ignore())
.ForMember(dest => dest.ActivityLog, mo => mo.Ignore());
Mapper.CreateMap<ActivityLogType, ActivityLogType>();
Mapper.CreateMap<ActivityLog, ActivityLogModel>()
.ForMember(dest => dest.ActivityLogTypeName, mo => mo.MapFrom(src=> src.ActivityLogType.Name))
.ForMember(dest => dest.CustomerName, mo => mo.MapFrom(src =>src.Customer.Email))
.ForMember(dest => dest.CreatedOn, mo => mo.Ignore());
出现的Exception就是CreateMap导致的,红色部分是下载的代码
// Mapper.CreateMap<ActivityLogType,ActivityLogType>();
Mapper.CreateMap<ActivityLogType,ActivityLogTypeModel>();
以上是调试一次NopCommerce发布版本中关于Map的Bug的过程。
更多资料,请参考:https://github.com/AutoMapper/AutoMapper