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

       

       

       

       

       

       

       

       

       

       

       

       

       

       

  • 相关阅读:
    e3.tree参考手册
    fckeditor使用详解
    提示constructor无法location的原因
    无限联动下拉框使用步骤
    动态sql构建的过程
    xsqlbuilder使用说明
    处理date类型对象的方式
    wdatepicker使用指南
    How to reclaim space in InnoDB when innodb_file_per_table is ON
    Bash script: report largest InnoDB files
  • 原文地址:https://www.cnblogs.com/mrfang/p/10806804.html
Copyright © 2020-2023  润新知