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()); } } |
- 指定映射字段
在实际的业务环境中,我们的源类型和目标类型的字段不可能一对一的匹配,这个时候我们就需要来指定他们的实际映射关系。如示例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 属性进行匹配)
APS.NET MVC + EF (06)---模型的更多相关文章
- APS.NET MVC + EF (08)---数据注解和验证
对于Web开发人员来说,用户输入验证一直是一个挑战.不仅在客户端浏览器中需要执行验证逻辑,在服务器端也需要执行.如果觉得验证是令人望而生畏的繁杂琐事,ASP.NET MVC框架提供了数据注解的方式帮助 ...
- APS.NET MVC + EF (07)---表单和HTML辅助方法
在ASP.NET MVC中,可以借助HtmlHelper 对象来输出页面内容,提高开发效率.下面,我们将介绍一些常用的辅助方法. 7.1 HTML辅助方法 BeginForm 该辅助方法主要用来产生& ...
- APS.NET MVC + EF (05)---控制器
Controller(控制器)在ASP.NET MVC中负责控制所有客户端与服务端的交互,并且负责协调Model与View之间数据传递,是ASP.NET MVC框架核心.Controller为ASP. ...
- APS.NET MVC + EF (04)---路由和数据传递
4.1 视图引擎 ASP.NET MVC 提供两种视图引擎:ASPX(C#)和Razor(CSHTML),推荐使用Razor. 4.1.1 Razor的语法 在Razor视图中,所有的服务器端代码都是 ...
- APS.NET MVC + EF (03)---初始MVC
3.1 MVC简介 MVC(Model-View-Controller,模型—视图—控制器模式)用于表示一种软件架构模式.它把软件系统分为三个基本部分:模型(Model),视图(View)和控制器(C ...
- APS.NET MVC + EF (02)---深入理解ADO.NET Entity Framework
2.7 深入理解Entity Framework 性能问题几乎是一切ORM框架的通病,对于EF来说,引起性能低的原因主要在以下几个方面. 复杂的对象管理机制为了在.NET中更好地管理模型对象,EF提供 ...
- APS.NET MVC + EF (02)---ADO.NET Entity FrameWork
2.1 Entity Framework简介 Ado.net Entity Framework 是Microsoft推出的ORM框架. 2.1.1 什么是ORM 对象关系映射(Object Relat ...
- APS.NET MVC + EF (14)---项目框架搭建
一:框架搭建 1:先创建Model. 2:创建数据访问接口层.IUserInfoDal 在该接口中定义了常见的方法CURD以及分页方法. public interface IUserInfoD ...
- APS.NET MVC + EF (11)---过滤器
过滤器本质就是对动作方法的执行过程进行干预,这种干预可以影响动作方法执行的各个过程.ASP.NET MVC 提供了4种类型的接口,并在接口中定义了各种成员,代表代码执行的各个阶段,这些接口和成员如表1 ...
随机推荐
- 全栈工程师对Python面试中is和==区别的详细解说!看完真的学到了!
面试实习生的时候,当问到 is 和 == 的区别时,很多同学都答不上来,搞不清两者什么时候返回一致,什么时候返回不一致.本文我们来看一下这两者的区别. 我们先来看几个例子: a = "hel ...
- html5+css+js简单了解
最近敲了敲HTML5的代码,感觉真的是很吸引人的东西,反正我是非常喜欢的,所以想写一点关于HTML的东xi首先呢我了解的不多,所以也是想写一点点我对它的认识.说起HTML5是打开Pycharm敲pyt ...
- 剑指offer 15:链表的倒数第k个节点
题目描述 输入一个链表,输出该链表中倒数第k个结点. 解题思路 使用快慢指针法,让快指针先走k步,然后再让慢指针开始走,当快指针到达链表尾部时,慢指针刚好到达倒数第k个节点. C++代码实现: /* ...
- Apache配置https
Apache配置https 之前一直用的是Tomcat,今天突然接到任务要给Apache配置https证书,因为小程序要用.下面把过程列出来以备后续查看. 1.首先你得有ssl证书,没有的可以去购买, ...
- mac上安装npm
检查brew -v是否安装了homebrew这个macOS 缺失的软件包的管理器.如果安装,跳转到第3步,否则跳转到第二步: 安装homebrew.安装跳转到官网指导.等待安装好之后,输入brew - ...
- python获得多个输入值
我们都知道python的input()函数是以字符串的形式输入的,这就产生了一个问题:当我们在一行内输入多个数值时,input()不会去判断输入元素个数,它只管把这行输入以字符串的形式输入,因此我们要 ...
- JAVA中this和super用法
参考网上资料和自行理解总结java中this和super中各自用法及其差异 <一>. this的用法 构造方法是创建java对象的重要途径,通过new关键字调用构造器时,构造器返回该类的对 ...
- 组装数据--相同的clusterID合并在一起 左边是a接口 右边是B接口如 [{a接口},{b接口}]
组装成这种 var BJData = [ [{"city": "无锡市","clusterID": 1, "y": 3 ...
- 9.Java基础_for/while/do-while循环
/* for循环(同C++) 初始化变量的作用域为循环体 出了循环体,初始化的局部变量消失 for(初始化;条件判断;条件控制){ 循环体; } while循环 while(条件判断){ 循环体; } ...
- luoguP3531 [POI2012]LIT-Letters
(https://www.luogu.org/problem/P3531) 注意编号 #include<cstdio> #include<algorithm> #include ...