在實際開發中,模型每每被劃分爲視圖模型和業務模型兩部分,視圖模型靠近視圖,業務模型靠近業務,可是在具體編碼上,它們之間並非隔離的。mvc
模型大多數時候都是用來傳遞數據的。然而即便在傳遞數據這一點上,也能夠看出,視圖須要的模型更加靈活一點,由於視圖變化性更大,而處理業務的模型更加穩定一些。所以,在實際開發中,每每有視圖模型和業務模型的區分。在實際開發中,爲了體現邏輯的分離,每每是視圖模型和業務模型分別定義。app
例如,在傳統三層開發中,咱們定義的實體類,能夠看做是業務模型的定義,在開發視圖時,可能會開發各類和User相關的視圖,如用戶註冊視圖、用戶狀態列表視圖、登陸視圖,這時候每每根據視圖構造不一樣的模型,由於它們依賴的數據都不太同樣,這些模型可稱爲視圖模型。 框架
這種方式的好處就是可讓業務模型比較穩定,不會由於視圖的變動而頻繁地去修改業務模型。可是從另外一方面來看,這種分離的方式也會有壞處。壞處之一就是帶來不少重複的代碼。另外一個壞處就是在動做方法中,模型自動綁定完視圖模型後,還須要再手動編碼把視圖模型映射到業務模型,帶來額外的工做量。 asp.net
在小型項目開發中,爲了簡化代碼,並不會徹底區分視圖模型和業務模型,但不意味着實際開發都這樣作。 工具
AutoMapper 是一個可以實現由一個對象到另外一個對象間映射的輕量級框架,利用AutoMapper框架可讓咱們從視圖模型到業務模型轉換的繁瑣工做中解放出來。編碼
AutoMapper 框架是基於約定的。 spa
新建asp.net mvc 項目 AutoMapperExample,點擊 工具→NuGetB包管理器→管理解決方案的NuGet程序包,在彈出的界面中,搜索autoMapper,在搜索出的程序包而後安裝。.net
咱們以常見的用戶角色案例來說解AutoMapper 的使用。對象
首先咱們建立角色和用戶兩個類。代碼以下。其中User類中的Role屬性是對Role類的引用。 開發
//角色 public class Role { public int Id { get; set; } public string Name { get; set; } } //用戶 public class User { public int Id { get; set; } public string LoginName { get; set; } public string LoginPwd { get; set; } public string Phone { get; set; } public int RoleId { get; set; } public Role Role { get; set; } } |
在建立註冊用戶時所需的視圖模型。代碼以下。
//註冊視圖中使用的視圖模型 public class RegUserVM { public int Id { get; set; } public string LoginName { get; set; } public string LoginPwd { get; set; } public string ConfirmPwd { get; set; } public string Phone { get; set; } public int RoleId { get; set; } } |
在視圖模型中增長了ConfirmPwd屬性,並將Role屬性去除。
接下來咱們在程序中新建AutoMapper文件夾,用於存放對象映射的類,該文件夾下新建類AutoMapperConfig,該類處理全部的對象映射,即從一個對象轉化到另外一個對象。如示例1所示。
示例1
using AutoMapper; //引用命名空間 public class AutoMapperConfig { public static void Config() { Mapper.Initialize(cfg => cfg.CreateMap<RegUserVM, User>()); } } |
Mapper.Initialize()方法執行AutoMapper的初始化操做,此操做在一個應用程序中只能執行一次.在初始化方法中能夠初始化映射中的任何操做。
CreateMap()泛型方法,用來建立兩個類型的映射,第一個類型爲原類型,第二個類型爲目標類型。在這裏配置爲將視圖模型映射爲業務模型。
而後,在項目的Global.asax文件的Application_Start()方法中調用該靜態方法。代碼以下所示。
protected void Application_Start() { //調用AutoMapper配置 AutoMapper.AutoMapperConfig.Config();
AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); } |
至此,全部AutoMapper的配置所有配置完成。
下面咱們完成用戶註冊功能。在控制器中建立兩個Action。如示例2所示。
示例2
[HttpGet] public ActionResult Register() { return View(); } [HttpPost] public ActionResult Register(RegUserVM userVM) { //將視圖模型對象映射爲業務模型對象 User user = Mapper.Map<User>(userVM); if (UserManager.Add(user)) { return RedirectToAction("Login"); } return View(); } |
Mapper.Map<S,T> 執行映射方法 S爲源類型,T爲目標類型,參數爲源類型。
示例2中,AutoMapper 根據字段名稱去自動對應,並忽略大小寫。咱們應用 AutoMapper 省去了繁瑣的賦值操做。
在AutoMapper中 ReverseMap() 方法能夠配置爲反向映射。如示例3所示。
示例3
public class AutoMapperConfig { public static void Config() { Mapper.Initialize(cfg => cfg.CreateMap<RegUserVM, User>().ReverseMap()); } } |
在實際的業務環境中,咱們的源類型和目標類型的字段不可能一對一的匹配,這個時候咱們就須要來指定他們的實際映射關係。如示例3所示。
示例3
//源類型 public class User { public int Id { get; set; } public string LoginName { get; set; } public string LoginPwd { get; set; } public string Phone { get; set; } public int RoleId { get; set; } public Role Role { get; set; } } //源目標類型 public class UserVM { public int UserId { get; set; } public string UserName { get; set; } public string RoleName { get; set; } }
public static void Config() { Mapper.Initialize(cfg => { cfg.CreateMap<RegUserVM, User>().ReverseMap(); cfg.CreateMap<User, ListUserVM>().ReverseMap();
cfg.CreateMap<User, UserVM>() .ForMember(vm => vm.UserId, opt => opt.MapFrom(s => s.Id)) //指定映射 .ForMember(vm=>vm.UserName,opt=>opt.MapFrom(s=>s.LoginName)) .ReverseMap()); }); }
|
ForMember()方法用來配置匹配信息。參數1:目標類型屬性的表達式,參數2:執行操做的選擇。
AutoMapper中容許設置一個備用值來代替源類型中的空值。如示例4所示。
示例4
public static void Config() { Mapper.Initialize(cfg => { cfg.CreateMap<RegUserVM, User>().ReverseMap(); cfg.CreateMap<User, ListUserVM>().ReverseMap();
cfg.CreateMap<User, UserVM>() .ForMember(vm => vm.UserId, opt => opt.MapFrom(s => s.Id)) .ForMember(vm=>vm.UserName,opt=>opt.MapFrom(s=>s.LoginName)) .ForMember(vm => vm.RoleName, opt => opt.NullSubstitute("普通用戶")).ReverseMap()); }); } |
在AutoMapper中, 若是對目標類型上的任何屬性,方法或以"Get"爲前綴的方法不存在源類型上,則AutoMapper會將目標成員名稱拆分爲單個單詞。
例如,在顯示用戶信息時,咱們只想顯示用戶的登陸名、電話和角色名稱三個屬性,代碼如示例5所示。
示例5
// 顯示用戶信息的視圖模型 public class ListUserVM { public int Id { get; set; } public string LoginName { get; set; } public string Phone { get; set; } public string RoleName { get; set; } } // AutoMapper配置 public static void Config() { Mapper.Initialize(cfg => { cfg.CreateMap<RegUserVM, User>().ReverseMap(); cfg.CreateMap<User, ListUserVM>().ReverseMap(); }); } // 控制器方法 public ActionResult Index() { Role role = new Role() { Id = 1, Name = "管理員" }; User user = new User() { Id = 1, LoginName = "admin", Phone = "111", Role=role }; ListUserVM userVM = Mapper.Map<ListUserVM>(user); return View(userVM); } |
程序運行後,userVM 對象的 RoleName 屬性會被賦值爲"管理員"。(RoleName屬性會和User類的 Role.Name 屬性進行匹配)