AutoMapper是用来解决对象之间映射转换的类库。对于我们开发人员来说,写对象之间互相转换的代码是一件极其浪费生命的事情,AutoMapper能够帮助我们节省不少时间。 一. AutoMapper解决了什么问题?要问AutoMapper解决了什么问题? 难道不是对象映射转换的问题吗? 在现代的软件开发中,项目的层级更加的细分,而不同层级之间对于对象的需求是有区别的,这就需要在不同层级间传递数据的时候,必须要转换数据。 举一些实际具体的例子: 那么问题是,谁来弥补它们之间的鸿沟?DTO(Data Transfer Object)——数据传输对象。而AutoMapper就是解决其中涉及到的数据对象转换的工具。 在实际开发中,如果你还可以直接在Business层或者界面层直接使用持久层的对象,因为你认为这个关系不大,整个项目都是你自己控制的,虽然 dirty,但是quick. 作为一个有些洁癖的程序员,我还是建议使用DTO在不同层级之间传递数据。因为当你做更高层级开发的时候,比如开发web service,WCF,Web API这些为系统外部提供接口的开发时候,你就回明白这些好的习惯和思维能够帮助你更加好的设计这些外部接口。 二. AutoMapper如何使用?先来看一个简单的例子,这个例子是定义Order对象到OrderDto对象之间的映射。(我们把Order称呼为源类,OrderDto称呼为目标类) Mapper.CreateMap<Order, OrderDto>();//创建映射关系Order –> OrderDto OrderDto dto = Mapper.Map<OrderDto>(order);//使用Map方法,直接将order对象装换成OrderDto对象 智能匹配 AutoMapper能够自动识别和匹配大部分对象属性:
自定义匹配规则 AutoMapper还支持自定义匹配规则 Mapper.CreateMap<CalendarEvent, CalendarEventForm>() //属性匹配,匹配源类中WorkEvent.Date到EventDate .ForMember(dest => dest.EventDate, opt => opt.MapFrom(src => src.WorkEvent.Date)) .ForMember(dest => dest.SomeValue, opt => opt.Ignore())//忽略目标类中的属性 .ForMember(dest => dest.TotalAmount, opt => opt.MapFrom(src => src.TotalAmount ?? 0))//复杂的匹配 .ForMember(dest => dest.OrderDate, opt => opt.UserValue<DateTime>(DateTime.Now));固定值匹配 测试 Mapper.AssertConfigurationIsValid(); 三. AutoMapper处理多对一映射我们开篇提到的问题中,说到界面显示User的name, email, 还有用户的考勤信息,而这些信息来自于2张不同的表。这就涉及到了多对一映射的问题,2个持久层对象需要映射到一个界面显示层的对象。 假设我们的持久层对象是这样的: public class User { public int Id { get; set; } public string Name { get; set; } public string Email { get; set; } public string Passworkd { get; set; } public DateTime Birthday { get; set; } } public class Evaluation { public int Id { get; set; } public int Score { get; set; } } 在Asp.net MVC中,我的界面显示层的ViewModel是这样的 public class UserViewModel { public int Id { get; set; } public string Name { get; set; } public string Email { get; set; } public int Score { get; set; } } 接下来,为了达到多对一的映射的目的,我们创建这个EntityMapper类 public static class EntityMapper { public static T Map<T>(params object[] sources) where T : class { if (!sources.Any()) { return default(T); } var initialSource = sources[0]; var mappingResult = Map<T>(initialSource); // Now map the remaining source objects if (sources.Count() > 1) { Map(mappingResult, sources.Skip(1).ToArray()); } return mappingResult; } private static void Map(object destination, params object[] sources) { if (!sources.Any()) { return; } var destinationType = destination.GetType(); foreach (var source in sources) { var sourceType = source.GetType(); Mapper.Map(source, destination, sourceType, destinationType); } } private static T Map<T>(object source) where T : class { var destinationType = typeof(T); var sourceType = source.GetType(); var mappingResult = Mapper.Map(source, sourceType, destinationType); return mappingResult as T; } } 为了实现多个源对象映射一个目标对象,我们使用了AutoMapper的方法,从不同的源对象逐一匹配一个已经存在的目标对象。下面是实际使用在MVC中的代码: public ActionResult Index() { var userId = 23, var user = _userRepository.Get(userId); var score = _scoreRepository.GetScore(userId); var userViewModel = EntityMapper.Map<UserViewModel>(user, score); return this.View(userViewModel); } 四. 使用Profile在Asp.net MVC项目中配置AutoMapperProfile是AutoMapper中用来分离类型映射定义的,这样可以让我们的定义AutoMapper类型匹配的代码可以更加分散,合理和易于管理。 利用Profile, 我们可以更加优雅的在MVC项目中使用我们的AutoMapper. 下面是具体的方法: 1. 在不同层中定义Profile,只定义本层中的类型映射 继承AutoMapping的Profile类,重写ProfileName属性和Configure()方法。 public class ViewModelMappingProfile: Profile { public override string ProfileName { get { return GetType().Name; } } protected override void Configure() { Mapper.CreateMap...... } } 2. 创建AutoMapperConfiguration, 提供静态方法Configure,一次加载所有层中Profile定义 public class AutoMapperConfiguration { public static void Configure() { Mapper.Initialize(x => x.AddProfile<ViewModelMappingProfile>()); Mapper.AssertConfigurationIsValid(); } } 3. 在Global.cs文件中执行 最后,在Global.cs文件中程序启动前,调用该方法 AutoMapperConfiguration.Configuration() |
|
来自: ThinkTank_引擎 > 《automapper》