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 属性进行匹配)

原文地址:https://www.cnblogs.com/mrfang/p/10806804.html

时间: 2024-11-05 19:31:14

APS.NET MVC + EF (06)---模型的相关文章

APS.NET MVC + EF (03)---初始MVC

3.1 MVC简介 MVC(Model-View-Controller,模型—视图—控制器模式)用于表示一种软件架构模式.它把软件系统分为三个基本部分:模型(Model),视图(View)和控制器(Controller).Asp.net MVC是微软提供的MVC开发框架. MVC将UI层分为了三个部分: 模型:一组类,描述了要处理的数据以及修改和操作数据的业务规则. 视图:定义应用程序界面的显示方式. 控制类:一组类,用于处理来自用户.整个应用程序流以及特定应用程序逻辑的通信. 3.2 第一个A

APS.NET MVC + EF (04)---路由和数据传递

4.1 视图引擎 ASP.NET MVC 提供两种视图引擎:ASPX(C#)和Razor(CSHTML),推荐使用Razor. 4.1.1 Razor的语法 在Razor视图中,所有的服务器端代码都是围绕@展开的,下面介绍@使用的各种语法形式和应用情况. @( expression) 或 @ expression @是Razor中的一个重要符号,它被定义为Razor服务器代码块的开始符号.例如,我们可以在View中直接写C#代码输出日期 <p> @Datetime.Now.ToStirng()

APS.NET MVC + EF (00)---C#基础

命名参数 命名参数是把参数附上参数名称,这样在调用方法的时候不必按照原来的参数顺序填写参数,只需要对应好参数的名称也能完成方法调用. static void Main(string[] args) { Console.WriteLine(ShowComputer("i3 370M","2G","320G")); Console.WriteLine(ShowComputer(disk: "320G", cpu: "i3

APS.NET MVC + EF (01)---Linq和Lambda表达式

1.1 Linq介绍 LINQ全称 Language Integrated Query(语言集成查询).为我们提供一种统一的方式来查询和操作各种数据. LINQ to Object:是针对实现了IEnumerable<T>的对象的LINQ: LINQ to SQL:是针对关系数据库的LINQ: LINQ to XML:是针对XML文档的LINQ. LINQ除了提供一个统一的API来操作各种数据,并且为我们提供了编译时类型检查和动态创建查询表达式的能力. LINQ查询时有两种语法可供选择:查询表

ASP.NET MVC+EF框架+EasyUI实现权限管理系列

http://www.cnblogs.com/hanyinglong/archive/2013/03/22/2976478.html ASP.NET MVC+EF框架+EasyUI实现权限管理系列之开篇 前言:博客又有一段时间没有更新了,心里感觉这段时间空空的,好像什么都没有学下,所以就想写博客,所以就有了这个系列,这里当然也要感谢大家了,因这个 项目我已经上传了,得到了很多网友的评价,也有好多人发邮件给我说这个框架容易出现问题,不能访问,这也是支持我写这个系列的动力,我将这个项目写成一个 系列

ASP.NET MVC+EF框架+EasyUI实现权限管理系列之开篇

原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列之开篇 前言:博客又有一段时间没有更新了,心里感觉这段时间空空的,好像什么都没有学下,所以就想写博客,所以就有了这个系列,这里当然也要感谢大家了,因这个项目我已经上传了,得到了很多网友的评价,也有好多人发邮件给我说这个框架容易出现问题,不能访问,这也是支持我写这个系列的动力,我将这个项目写成一个系列,可能要很长时间吧,但是我肯定会一直坚持,如果我哪里写的不好欢迎大家指出我们共同学习,而且我理解的也不是很透彻,所以我想在写这样一遍

ASP.NET MVC+EF框架+EasyUI实现权限管理

4.为什么使用MVC而不是用WebForm呢? (1)为什么使用MVC而不是用WebForm呢?这个是我临时想的,因为我就是想说明一下WebForm和MVC的优缺点,来可以使大家能够更好地理解 MVC和WebForm,而不像某些人说MVC会替代WebForm,我个人认为这个可能性很小,因为各有各的好处,看在哪里使用吧,下面我就简单介绍下 WebForm和MVC的优缺点. (2)WebForm介绍 1)优点 1):支持事件模型,取决于微软提供了丰富的服务器端组建,WebForm可以快速的搭建Web

ASP.NET MVC+EF框架+EasyUI实现权限管理系列(5)-前台JqueryEasyUI前台实现

原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(5)-前台JqueryEasyUI前台实现 ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇)   (1):框架搭建    (2):数据库访问层的设计Demo    (3):面向接口编程   (4 ):业务逻辑层的封装 前言:今天经理买了一个诺基亚的Windows Phone 8系统,特感兴趣,所以在哪里看了很长时间,这篇文章就写的有点迟, 从这个Demo开始到现在我已经写了4篇博客了,终于可以看到页面的东

ASP.NET MVC+EF框架+EasyUI实现权限管理系列(2)-数据库访问层的设计Demo

原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(2)-数据库访问层的设计Demo ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇) (1)框架搭建 前言:这篇博客我们继续来实现我的权限系列,这个博客一段时间也没有写了,重点是我在想还写不写,最终我决定还是写下去,因为我们是为了学习,当别人提出意见的时候,我们可以参考和采纳,但是我们不一定非要采纳,上几篇博客大家都说用CodeFirst来实现,是啊,现在基本很少有人用我的这种方法来实现了,都是用CodeF