你的位置:首页 > ASP.net教程

[ASP.net教程]使用Ajax请求MVC查出的EF转成DTO的数据?

背景:想要使用Ajax来获取列表数据:

记笔记模式开始:

首先数据库脚本:

USE [DB_USERS]GO/****** Object: Table [dbo].[Student]  Script Date: 11/06/2015 00:01:52 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOSET ANSI_PADDING ONGOCREATE TABLE [dbo].[Student](  [s_ID] [INT] IDENTITY(1,1) NOT NULL,  [s_Name] [NVARCHAR](10) NULL,  [s_Sex] [CHAR](2) NULL,  [s_Age] [INT] NULL,  [c_ID] [INT] NOT NULL, CONSTRAINT [PK__Studnet__2F3DA3BC267ABA7A] PRIMARY KEY CLUSTERED (  [s_ID] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]GOSET ANSI_PADDING OFFGOALTER TABLE [dbo].[Student] WITH CHECK ADD FOREIGN KEY([c_ID])REFERENCES [dbo].[Classes] ([c_ID])GO

USE [DB_USERS]GO/****** Object: Table [dbo].[Classes]  Script Date: 11/06/2015 00:02:15 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [dbo].[Classes](  [c_ID] [INT] NOT NULL,  [c_Name] [NVARCHAR](50) NULL,PRIMARY KEY CLUSTERED (  [c_ID] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]GO

然后新建MVC的项目:我先把框架图贴出来:

然后贴出后台的代码;

控制器的代码:

using MVCAjax01.Models;using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;namespace MVCAjax01.Controllers{  public class StudentController : Controller  {    ModelDB db = new ModelDB();    /// <summary>    /// 生成学员列表页面    /// </summary>    /// <returns></returns>    public ActionResult Index()    {      return View();    }    /// <summary>    /// 根据页码加载数据    /// </summary>    /// <param name="id">id参数其实传到页面中对应的pageIndex,那为什么用id,因为路由中是这么配置的</param>    /// <returns></returns>    public ActionResult List(int id)    {      int pageIndex = id;      int pageSize = 3;      //查询学员分页数据      //分页的步骤:orderby-->Skip((页码-1)*页容量)--->Take(页容量),最后tolist().      //List<Student> list = db.Students.OrderBy(s => s.s_ID).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();      //换成DTO实体      //这样写就有问题了,db.Students的Students还是Model下面的EFstudent实体,这个时候可以这样改一下。      //List<MVCAjax01.Models.DTO.Student> list = db.Students.OrderBy(s => s.s_ID).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();      //修正之后的(使用select方法映射一下,转成DTO,在里面要new一下每个DTO)      //将EF查询出来的F实体集合转成DTO(data transfer object)实体集合      //List<MVCAjax01.Models.DTO.Student> list = db.Students.OrderBy(s => s.s_ID).Skip((pageIndex - 1) * pageSize).Take(pageSize).Select(s => new Models.DTO.Student() {       //s_ID=s.s_ID,      //s_Name=s.s_Name,      //s_Age=s.s_Age,      //s_Sex=s.s_Sex,      //c_ID=s.c_ID,      //Class=s.Class            //}).ToList();  //TIPS:这里一个一个属性写太累了,我们可以写一个方法实体类转DTO的方法,在Model里添加一个类,写方法。      //在分布类中写了DTO转化方法之后,这边就不用select了。直接这样写。      //List<MVCAjax01.Models.DTO.Student> list = db.Students.OrderBy(s => s.s_ID).Skip((pageIndex - 1) * pageSize).Take(pageSize).Select(            //  s=>s.ToDto()  //这样写还有个问题,就是Class属性刚才没有设置。这个时候还要做修改。      //).ToList();      //这个时候,可以这样修改, 但这样写还有问题,就是EF中的Class属性和DTO中的属性还是不一样,所以我们还是在DTO中做修改,同样我们需要为Class设置添加DTO类      //List<MVCAjax01.Models.DTO.Student> list = db.Students.OrderBy(s => s.s_ID).Skip((pageIndex - 1) * pageSize).Take(pageSize).Select(      //s => { var sDTO = s.ToDto(); sDTO.Class = s.Class; return sDTO; }            //将EF查出来的集合转成DTO实体集合,并返回(关于使用DTO类的时候注意,类名不要和EF实体类一样,不然会报错。)      //然后,这边还有一个易错点:take方法之后必须要tolist,不然报错。      List<MVCAjax01.Models.DTO.StudentDTO> list = db.Students.OrderBy(s => s.s_ID).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList().Select(     s =>s.ToDto()     ).ToList();      //获取总行数(总数)      int rowCount = db.Students.Count();      //计算总页数      int pageCount = Convert.ToInt32(Math.Ceiling((rowCount * 1.0) / pageSize));      //生成Json格式的数据(如果自己生成就很麻烦,这个时候就自己添加一个类,做法;我们在Model文件夹下添加一个类)      #region 没有使用DTO的时候的版本      //没有使用DTO的时候的版本      ////操作:将数据封装到PagedDataModel 分页数据实体中      ////封装很简单啊,就是给属性赋值呗:      ////弄成泛型类之后,要指定是哪个类      //PagedDataModel<Student> pageModel = new PagedDataModel<Student>()      ////但不管怎么样,这个PagedDataModel实体中,仅仅是包含分页的数据相关的数据而已,那你转成Json格式的数据,你要把他转哇,      ////发到浏览器去,浏览器肯定想知道,到底是成功还是没成功啊,状态是什么啊,所以我们还要准备一个类,这个时候就是JsonModel      ////我们再在Model文件夹下添加一个JosnModel类      //{      //  //data属性弄成泛型之后,这边就可以直接将list赋值给data了。      //  Data = list,      //  PageCount = pageCount,      //  PageSize = pageSize,      //  RowCount = rowCount,      //  PageIndex = pageSize      //};      #endregion      #region 使用DTO之后的版本修改      //操作:将数据封装到PagedDataModel 分页数据实体中      //封装很简单啊,就是给属性赋值呗:      //弄成泛型类之后,要指定是哪个类      PagedDataModel<Models.DTO.StudentDTO> pageModel = new PagedDataModel<Models.DTO.StudentDTO>()      //但不管怎么样,这个PagedDataModel实体中,仅仅是包含分页的数据相关的数据而已,那你转成Json格式的数据,你要把他转哇,      //发到浏览器去,浏览器肯定想知道,到底是成功还是没成功啊,状态是什么啊,所以我们还要准备一个类,这个时候就是JsonModel      //我们再在Model文件夹下添加一个JosnModel类      {        //data属性弄成泛型之后,这边就可以直接将list赋值给data了。        Data = list,        PageCount = pageCount,        PageSize = pageSize,        RowCount = rowCount,        PageIndex = pageSize      };            //总结;上面的查询Student数据的时候,用EF查出来之后,转为了DTO的集合,(本来查出来的是EF的学员集合)      #endregion      //将分页数据实体,封装到json 标准格式实体中      JsonModel jsonModel = new JsonModel()      {        Data = pageModel,        Message = "成功",        Status = "OK"        //BackUrl= 不给,没东西嘛!      };      #region 这两行代码,相当于是json 方法      // System.Web.Script.Serialization.JavaScriptSerializer jsS = new System.Web.Script.Serialization.JavaScriptSerializer();      //string str= jsS.Serialize(list);      #endregion      //生成json格式的数据(通过json方法)      //这个方法,内部其实就是帮我们调用JavaScriptSerializer的序列化方法,正是因为调用这个方法,所以我们在这里处理数据的时候,就会报错:循环引用。      //EF生成的实体类,只是方便查询的,真正使用的时候,特别做序列化的时候,还是要转成我们自己的实体类,这种实体类,我们把他叫做DTO,我们在Model文件夹下,新建一个文件夹DTO,然后在里面继续添加类。。      //备注: 拿到DTO集合之后,这边序列化的时候,就不会报错了。      //此json方法,默认只允许Post请求      return Json(jsonModel,JsonRequestBehavior.AllowGet);         }  }}

Index视图的代码:

@{  ViewBag.Title = "学员列表";[email protected] headSection{  <script type="text/javascript">    $(function () {      //关闭Jquery的浏览器缓存      //关闭缓存之后,每次都会发送一个数据到服务器获取数据      $.ajaxSetup({ cache: false });      //请求第一页数据      LoadPageList(1);    });    //根据页码,异步请求数据    //我们读取页面的数据,是在服务端读取数据之后,直接生成HTML代码发过来,显示在表格里面好?还是在服务端拿到数据之后,先把数据转成Json,发到浏览器,然后浏览器根据json数据转化为HTML代码好?    //Josn好,Json的传输量小一点。    //用json 的话就直接$.getJSON(),或者$.get()            function LoadPageList(pageIndex)    {      //和getjson差不多,少了最后一个参数      //$.get("Student/List" + pageIndex, null, function (jsonData) {      //}, "json");      //注意:get请求是不是使用浏览器缓存?那我们最好把浏览器缓存清除掉比较好。      //技巧哦,可以使用一个全局的变量,把缓存关掉      $.getJSON("Student/List" + pageIndex, null, function (jsonData) {        alert(jsonData.msg);      });    }  </script>      }<table id="tbList">  <tr>    <th>ID</th>    <th>Name</th>    <th>Sex</th>    <th>Age</th>    <th>Class</th>    <th>Operate</th>  </tr></table>

View Code

 

然后就是每个DTO文件夹下的两个类的代码:

using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace MVCAjax01.Models.DTO{  /// <summary>  /// DTO类的关键点是,我们自己写的类,而不是那个代理类,在用的时候,我们举找到查询的时候的代码,稍微修改一下  ///   /// </summary>  public class ClassDTO  {    //public Class()    //{    //  this.Students = new HashSet<Student>();    //}    public int c_ID { get; set; }    public string c_Name { get; set; }    //同理这个属性也稍作修改,去掉virtual,其实班级里面,我们不知道有没有学员,要知道的话,可以去查,所以这个属性去掉,这里就注释吧    //public ICollection<Student> Students { get; set; }  }}

using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace MVCAjax01.Models.DTO{  ///DTO类的关键点是,我们自己写的类,而不是那个代理类,在用的时候,我们举找到查询的时候的代码,稍微修改一下  /// <summary>  /// 这里面的实体,和EF中的Student实体一样,直接copy过来。  /// </summary>  public class StudentDTO  {    public int s_ID { get; set; }    public string s_Name { get; set; }    public string s_Sex { get; set; }    public Nullable<int> s_Age { get; set; }    public int c_ID { get; set; }    //只不过这个属性稍作修改    public ClassDTO Class { get; set; }  }}

接着就是DTO转化的方法类:

using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace MVCAjax01.Models{  /// <summary>  /// 里面的名字要和EF一样,到时候合并为一个方法  /// </summary>  public partial class Student  {   #region 1.0版本 先不设置Claa属性    //将EF Student实体,转成DTO学员实体    //1.0版本 先不设置Claa属性    //public DTO.Student ToDto()    //{     // return new DTO.Student()    // {    // s_ID=this.s_ID,    // c_ID=this.c_ID,    // s_Sex=this.s_Sex,    // //Class=this.Class, 这里不能直接写,但这里可以不给,class是外键,需要的时候,查询的时候给。现在回到控制器    // s_Age=this.s_Age,    // s_Name=this.s_Name         // };     #endregion    #region 2.0 版本设置Class属性    public DTO.StudentDTO ToDto()    {      return new DTO.StudentDTO()      {        s_ID = this.s_ID,        c_ID = this.c_ID,        s_Sex = this.s_Sex,        //Class=this.Class, 这里不能直接写,但这里可以不给,class是外键,需要的时候,查询的时候给。现在回到控制器        s_Age = this.s_Age,        s_Name = this.s_Name,        Class = this.Class.ToDto()      };    #endregion    }  }}

 

using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace MVCAjax01.Models{  /// <summary>  /// 里面的名字要和EF一样,到时候合并为一个方法  /// </summary>  public partial class Class  {    public DTO.ClassDTO ToDto()    {      return new DTO.ClassDTO()      {        c_ID=this.c_ID,        c_Name=this.c_Name      };    }  }}

然后就是分页数据实体类:

using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace MVCAjax01.Models{  //里面要添加的属性,就是刚才计算的。  //写完之后,要序列化这个类。控制器中的操作:   //操作:将数据封装到PagedDataModel 分页数据实体中  /// <summary>  /// 分页数据实体  /// </summary>  public class PagedDataModel<T>  {    /// <summary>    /// 数据    /// </summary>    public List<T> Data { get; set; }  //这个data属性,应该用object类型,当然也可以使用泛型,具体:把类写作泛型类,返回data属性弄成泛型    /// <summary>    /// 页码(在这里可以设置或者不设置)    /// </summary>    public int PageIndex { get; set; }    /// <summary>    /// 页容量(在这里可以设置或者不设置)    /// </summary>    public int PageSize { get; set; }        /// <summary>    /// 总页数    /// </summary>    public int PageCount { get; set; }    /// <summary>    /// 总行数(总数)    /// </summary>    public int RowCount { get; set; }  }}

然后就是JsonModel实体类:

using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace MVCAjax01.Models{  /// <summary>  /// Json数据实体  /// </summary>  public class JsonModel  {    public object Data { get; set; }    public string Message { get; set; }    public string Status { get; set; }    public string BackUrl { get; set; }  }}

最后附上几幅图:


清远旅游需要多少钱广东清远旅游景点深圳去清远旅游要多少钱清远旅游景点大全深圳到清远旅游多少钱2015锦绣中华元旦活动?元旦深圳锦绣中华民俗村门票优惠价格? 冰雪撒欢季 你不知道的黑龙江民族美食风向标(组图) 2015顺德长鹿农庄元旦活动?元旦长鹿农庄门票优惠价格? 2015元旦佛山免费好玩景点有哪些佛山元旦带孩子家人去什么地方好玩? 小长假不虚度 来辽宁感受“蒸爷”气息 深圳锦绣中华万圣节刺激吗?锦绣中华万圣节门票价格? 秋天这样找虐才够味(组图) 天降长假哪里去 十种娱乐方式带你潮玩海南 2015年情人节上映的电影有什么?情人节电影推荐 2015年情人节怎么过?2015年情人节浪漫推荐 2015年情人节看什么电影? 情人节除了送玫瑰,还可以送什么花? 国庆峨眉山旅游温馨提示 十一去哪旅游 国庆峨眉山旅游费用 剪子弯山攻略 LT1270ACT#06PBF Datasheet LT1270ACT#06PBF Datasheet LT1374IR#TRPBF Datasheet LT1374IR#TRPBF Datasheet LT1510IS#TRPBF Datasheet LT1510IS#TRPBF Datasheet 东莞到回龙山滑雪场旅游 东莞到回龙山滑雪场旅游 东莞到回龙山滑雪场旅游 东莞到回龙天界山生态旅游景区旅游 东莞到回龙天界山生态旅游景区旅游 东莞到回龙天界山生态旅游景区旅游 东莞到回龙湾度假村旅游 东莞到回龙湾度假村旅游 东莞到回龙湾度假村旅游