APS.NET MVC + EF (06)---模型


在實際開發中,模型往往被划分為視圖模型和業務模型兩部分,視圖模型靠近視圖,業務模型靠近業務,但是在具體編碼上,它們之間並不是隔離的。

   

6.1 視圖模型和業務模型

模型大多數時候都是用來傳遞數據的。然而即使在傳遞數據這一點上,也可以看出,視圖需要的模型更加靈活一點,因為視圖變化性更大,而處理業務的模型更加穩定一些。因此,在實際開發中,往往有視圖模型和業務模型的區分。在實際開發中,為了體現邏輯的分離,往往是視圖模型和業務模型分別定義。

例如,在傳統三層開發中,我們定義的實體類,可以看作是業務模型的定義,在開發視圖時,可能會開發各種和User相關的視圖,如用戶注冊視圖、用戶狀態列表視圖、登錄視圖,這時候往往根據視圖構造不同的模型,因為它們依賴的數據都不太一樣,這些模型可稱為視圖模型。

這種方式的好處就是可以讓業務模型比較穩定,不會因為視圖的變更而頻繁地去修改業務模型。但是從另一方面來看,這種分離的方式也會有壞處。壞處之一就是帶來很多重復的代碼。另一個壞處就是在動作方法中,模型自動綁定完視圖模型后,還需要再手動編碼把視圖模型映射到業務模型,帶來額外的工作量。

在小型項目開發中,為了簡化代碼,並不會完全區分視圖模型和業務模型,但不意味着實際開發都這樣做。

   

6.2 AutoMapper框架

AutoMapper 是一個能夠實現由一個對象到另一個對象間映射的輕量級框架,利用AutoMapper框架可以讓我們從視圖模型到業務模型轉換的繁瑣工作中解放出來。

AutoMapper 框架是基於約定的。

   

6.2.1 AutoMapper 框架的安裝

新建asp.net mvc 項目 AutoMapperExample,點擊 工具→NuGetB包管理器→管理解決方案的NuGet程序包,在彈出的界面中,搜索autoMapper,在搜索出的程序包然后安裝。

   

6.2.2 AutoMapper 框架的使用

我們以常見的用戶角色案例來講解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 省去了繁瑣的賦值操作。

   

6.2.3 映射規則

  • 默認規則
    • 默認情況下,我們的"原類型"和"目標類型"是根據屬性名稱進行匹配映射的。
    • 如果在目標類型的屬性與源類型中配有對應的屬性,則映射失敗(為空)。
    • 在映射過程中,會執行自動類型轉換。(6.2.0以上版本)
  • 反向映射

    在AutoMapper中 ReverseMap() 方法可以配置為反向映射。如示例3所示。

示例3

public class AutoMapperConfig

{

public static void Config()

{

Mapper.Initialize(cfg =>

cfg.CreateMap<RegUserVM, User>().ReverseMap());

}

}

   

  1. 指定映射字段

在實際的業務環境中,我們的源類型和目標類型的字段不可能一對一的匹配,這個時候我們就需要來指定他們的實際映射關系。如示例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:執行操作的選擇。

  1. 空值替換

    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());

});

}

   

  1. 扁平化映射

    在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 屬性進行匹配)

   

   

   

   

   

   

   

   

   

   

   

   

   

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM