为了说明AutoMapper如何使用,我专门开设了一个专题来讲,如果您还没有查看该专题,请点击这里。既然系统地学习了AutoMapper,那么接下来就是该用它实战的时候了。今天,我们就来揭开AutoMapper如何在ABP框架中使用的面纱。
因为这里演示的是用ABP框架搭建的项目,本博客的讲解的前提是假设你有了ABP基础,所以,如果您还不了解ABP框架,请查看我的ABP框架的系列博客,请点击这里。
下面正式开始今天的讲解。
首先,让我们稍微回忆一下AutoMapper的知识点。
问:什么是AutoMapper?
答:AutoMapper翻译过来就是“自动映射工具”。它的作用就是将一个源类型映射成一个目标类型,比如Person——>PersonDto,User——>UserDto。
问:什么情况下使用AutoMapper?
答:一般在项目的开发中,经常需要将Entity实体映射成ModelDto或者ViewModel,这个时候,使用AutoMapper仅需要简单的配置,就可以实现这些需求,非常方便。
接下来,讲一下项目中的具体配置。
在我的ABP项目中,首先核心层有一个实体类TerminalDevices,类定义如下:
1 namespace Noah.ChargeStation.Core.Entities 2 { 3 //终端表 4 public class TerminalDevices : Entity 5 { 6 7 /// <summary> 8 /// 终端编码 9 /// </summary> 10 public virtual string Code 11 { 12 get; 13 set; 14 } 15 /// <summary> 16 /// IMEI 17 /// </summary> 18 public virtual string IMEI 19 { 20 get; 21 set; 22 } 23 /// <summary> 24 /// SIMCardNO 25 /// </summary> 26 public virtual string SIMCardNO 27 { 28 get; 29 set; 30 } 31 /// <summary> 32 /// InstallDate 33 /// </summary> 34 public virtual DateTime? InstallDate 35 { 36 get; 37 set; 38 } 39 /// <summary> 40 /// PlacePosition 41 /// </summary> 42 public virtual string PlacePosition 43 { 44 get; 45 set; 46 } 47 /// <summary> 48 /// Version 49 /// </summary> 50 public virtual int? Version 51 { 52 get; 53 set; 54 } 55 /// <summary> 56 /// TotalCoins 57 /// </summary> 58 public virtual int TotalCoins 59 { 60 get; 61 set; 62 } 63 /// <summary> 64 /// CurrentBoxCoins 65 /// </summary> 66 public virtual int CurrentBoxCoins 67 { 68 get; 69 set; 70 } 71 /// <summary> 72 /// 最小计费单位 73 /// </summary> 74 public virtual int MinimumUnit 75 { 76 get; 77 set; 78 } 79 /// <summary> 80 /// 充电时长 81 /// </summary> 82 public virtual int ChargeTime 83 { 84 get; 85 set; 86 } 87 /// <summary> 88 /// MoneyBoxCapacity 89 /// </summary> 90 public virtual int? MoneyBoxCapacity 91 { 92 get; 93 set; 94 } 95 /// <summary> 96 /// 终端名称 97 /// </summary> 98 public virtual string Name 99 { 100 get; 101 set; 102 } 103 /// <summary> 104 /// 终端类型:0--同城类终端 1--跨城类终端 105 /// </summary> 106 public virtual int? Type 107 { 108 get; 109 set; 110 } 111 /// <summary> 112 /// 所属城市 113 /// </summary> 114 public virtual int? CityID 115 { 116 get; 117 set; 118 } 119 /// <summary> 120 /// 所属运营商 121 /// </summary> 122 public virtual int? OperatorID 123 { 124 get; 125 set; 126 } 127 /// <summary> 128 /// 所属站台 129 /// </summary> 130 public virtual int? StationID 131 { 132 get; 133 set; 134 } 135 /// <summary> 136 /// 经度 137 /// </summary> 138 public virtual decimal? Longitude 139 { 140 get; 141 set; 142 } 143 /// <summary> 144 /// 纬度 145 /// </summary> 146 public virtual decimal? Latitude 147 { 148 get; 149 set; 150 } 151 /// <summary> 152 /// 支付宝二维码内容 153 /// </summary> 154 public virtual string AlipayEWMContent 155 { 156 get; 157 set; 158 } 159 /// <summary> 160 /// 支付宝二维码图片 161 /// </summary> 162 public virtual string AlipayEWMImage 163 { 164 get; 165 set; 166 } 167 /// <summary> 168 /// 微信二维码内容 169 /// </summary> 170 public virtual string WechatEWMContent 171 { 172 get; 173 set; 174 } 175 /// <summary> 176 /// 微信二维码图片 177 /// </summary> 178 public virtual string WechatEWMImage 179 { 180 get; 181 set; 182 } 183 /// <summary> 184 /// 正在充电数量 185 /// </summary> 186 public virtual int? ChargingNum 187 { 188 get; 189 set; 190 } 191 /// <summary> 192 /// 上次通讯时间 193 /// </summary> 194 public virtual DateTime? LastConnectTime 195 { 196 get; 197 set; 198 } 199 /// <summary> 200 /// 0--失联 1--正常 2--维修 3--维护4--下线 201 /// </summary> 202 public virtual int? Status 203 { 204 get; 205 set; 206 } 207 /// <summary> 208 /// SystemCode 209 /// </summary> 210 public virtual string SystemCode 211 { 212 get; 213 set; 214 } 215 /// <summary> 216 /// Certificate 217 /// </summary> 218 public virtual string Certificate 219 { 220 get; 221 set; 222 } 223 /// <summary> 224 /// 到期时间 225 /// </summary> 226 public virtual DateTime? DueDate 227 { 228 get; 229 set; 230 } 231 /// <summary> 232 /// 创建人 233 /// </summary> 234 public virtual string CreatedBy 235 { 236 get; 237 set; 238 } 239 /// <summary> 240 /// 创建日期 241 /// </summary> 242 public virtual DateTime? CreatedDate 243 { 244 get; 245 set; 246 } 247 /// <summary> 248 /// 最后更新人 249 /// </summary> 250 public virtual string UpdatedBy 251 { 252 get; 253 set; 254 } 255 /// <summary> 256 /// 最后更新日期 257 /// </summary> 258 public virtual DateTime? UpdatedDate 259 { 260 get; 261 set; 262 } 263 public TerminalDevices() 264 { 265 266 } 267 268 } 269 270 }
可以看到,仅一个实体类,就要将近300行的代码,但是在服务层或者展现层使用的时候,有些属性是不需要的,所以这时我们就要定义我们的Dto类了。
随后,我在ABP项目中的服务层定义了一个对应的TerminalDeviceDto类,定义如下:
1 namespace Noah.ChargeStation.Application.TerminalDevicesApp.Dto 2 { 3 public class TerminalDeviceDto:IDto 4 { 5 [DisplayName("设备编码")] 6 public string Code { get; set; } 7 public string IMEI { get; set; } 8 [DisplayName("SIM卡号")] 9 public string SIMCardNO { get; set; } 10 public string InstallDate { get; set; } 11 public string PlacePosition { get; set; } 12 public int Version { get; set; } 13 [DisplayName("总投币")] 14 public int TotalCoins { get; set; } 15 public int CurrentBoxCoins { get; set; } 16 public int MinimumUnit { get; set; } 17 public int ChargeTime { get; set; } 18 public int MoneyBoxCapacity { get; set; } 19 public string Name { get; set; } 20 public int Type { get; set; } 21 public int CityId { get; set; } 22 public int OperatorId { get; set; } 23 public int StationId { get; set; } 24 public decimal Longitude { get; set; } 25 public decimal Latitude { get; set; } 26 public string AlipayEWMContent { get; set; } 27 public string AlipayEWMImage { get; set; } 28 public string WechatEWMContent { get; set; } 29 public string WechatEWMImage { get; set; } 30 public int ChargingNum { get; set; } 31 public DateTime LastConnectTime { get; set; } 32 public int Status { get; set; } 33 public string SystemCode { get; set; } 34 public string Certificate { get; set; } 35 public DateTime DueDate { get; set; } 36 public string CreatedBy { get; set; } 37 public DateTime CreatedDate { get; set; } 38 public string UpdatedBy { get; set; } 39 public DateTime UpdatedDate { get; set; } 40 41 } 42 }
当然,这里的Dto类定义的属性跟你的具体业务相关,定义的属性还可能更少。
上面讲的是源类型和目标类型的定义,下面开始讲它们之间的映射配置。
首先,我在应用服务层新建一个文件夹取名“AutoMapper”,里面放跟AutoMapper配置相关的东西。
如图,新建一个类TerminalDeviceProfile(CityProfile类是我的另一个实体类对应的AutoMapper配置文件),定义如下:
namespace Noah.ChargeStation.Application.AutoMapper { public class CityProfile:Profile { protected override void Configure() { Mapper.Initialize(cfg => { cfg.CreateMap<Cities, CityDto>(); }); } } }
如果您对这么配置不清楚原因,请查看我的AutoMapper系列教程,点击查看。
再创建一个AutoMapperWebConfig静态类,定义如下:
namespace Noah.ChargeStation.Application.AutoMapper { public static class AutoMapperWebConfig { public static void Configure() { Mapper.Initialize(cfg => { cfg.AddProfile<CityProfile>(); cfg.AddProfile<TerminalDeviceProfile>(); }); Mapper.AssertConfigurationIsValid();//验证所有的映射配置是否都正常 } } }
接下来,在应用服务层的模块类中调用该静态类的静态方法,加载所有的AutoMapper配置信息。
namespace Noah.ChargeStation.Application { [DependsOn(typeof(ChargeStationCoreModule), typeof(AbpAutoMapperModule))] public class ChargeStationApplicationModule : AbpModule { public override void Initialize() { IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly()); AutoMapperWebConfig.Configure();//一次性加载所有映射配置 } } }
这里需要注意的是,AutoMapper的配置一般放在项目启动的时候进行加载且只加载一次就够了,而在ABP框架搭建的项目中,除了展现层(Web和WebAPI层),其他层都会有一个Module类(类名以Module结尾)。这些类都重写了父类AbpModule的Initialize方法,旨在模块初始化的时候调用,这样,映射的配置也在模块初始化的时候完成了。如果在一般的ASP.Net项目中,应该在全局配置文件Global.asax中的Application_Start方法中调用AutoMapper的配置方法,其他项目类似。
以后,想要添加配置信息时,只需要定义相应的XXProfile类,然后在AutoMapperWebConfig类中添加配置文件类就可以了。