1.重要:javaScriptSerializer 无法识别被序列化的对象里各种属性是否存在 循环依赖
(System,Web.Script.Serialization.JavaScriptSerializer)
所以,我们不能使用javaScriptSerializer 去序列化 EF 实体对象A 。
因为javaScriptSerializer 会循环 EF 实体对象 A 里的每个属性,想要根据此属性生成对应的Json字符串,但是,EF 实体A 的外键(导航)属性如果被访问,则自动去数据库获取,而这个导航属性对应的实体类 B 中可能又包含指向实体 A 的类型,那么,EF又会去加载 A 的数据,然后 A里又包含B。。。。。陷入死循环。。。
(参考2013-5-31-mvc)
2.后台如果取数据需要转换成json发送到前台如图,Class就不能获取数据。所以我们需要采用DTO
2.1.前台ajax请求Student数据
Stu/Index.cshtml
Stu/Index.cshtml @{ ViewBag.Title = "学员列表"; } @section headSection{ <script type="text/javascript"> $(function () { //0.关闭Jquery的浏览器缓存 $.ajaxSetup({ cache: false }); loadPageList(1); }); //根据页码 异步请求数据 function loadPageList(pageIndex) { $.get("/Stu/List/" + pageIndex, null, function(jsonData) { alert(jsonData.msg); },"json"); } </script> } <table border="1" cellspacing="0" cellpadding="0" width="100%"> <tr> <th>ID</th> <th>班级名</th> <th>姓名</th> <th>性别</th> <th>操作</th> </tr> <tr> </tr> </table>
2.2.后台获取数据
//根据页码加载数据 此方法的Id其实是页码 public ActionResult List(int id) { //页码 int pageIndex = id; //页容量 int pageSize = 2; //2.1 根据页码获取分页数据 List<Models.Student> list = db.Students.Include("Class").OrderBy(s => s.StudentID) .Take(pageSize).Skip((pageIndex - 1) * pageSize).ToList(); //2.2 获取总行数 int rowCount = db.Students.Count(); //2.3 计算总页数 int pageCount = Convert.ToInt32(Math.Ceiling((rowCount*1.0)/pageSize)); return null; }
3.这个时候我们来创建DTO
注意:
1.去掉virtual
public virtual Class Class { get; set; }
2.//public class Class{...} //报错
//这里ClassDTO.cs不能是用Class.cs同名类,因为EF不认识,会报下列错误
//CLR到EDM的类型映射不明确,因为多个CLR类型与EDM类型“Class”匹配,
StudentDTO.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace _06MVCAjax_CodeFirst.Models.DTO { //public class Student{...} //报错 //这里StudentDTO.cs不能是用Student.cs同名类,因为EF不认识,会报下列错误 //CLR到EDM的类型映射不明确,因为多个CLR类型与EDM类型“Student”匹配, public class StudentDTO { public int StudentID { get; set; } public Nullable<int> Cid { get; set; } public string Name { get; set; } public string Gender { get; set; } public Nullable<int> Isdel { get; set; } public Nullable<System.DateTime> AddTime { get; set; } //注意这里是ClassDTO类型 public ClassDTO Class { get; set; } } }
ClassDTO.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace _06MVCAjax_CodeFirst.Models.DTO { //public class Class{...} //报错 //这里ClassDTO.cs不能是用Class.cs同名类,因为EF不认识,会报下列错误 //CLR到EDM的类型映射不明确,因为多个CLR类型与EDM类型“Class”匹配, public class ClassDTO { public ClassDTO() { this.Students = new List<Student>(); } public int Cid { get; set; } public string CName { get; set; } public Nullable<int> CCount { get; set; } public string CImg { get; set; } public string CIsdel { get; set; } public Nullable<System.DateTime> Addtime { get; set; } public ICollection<Student> Students { get; set; } } }
4.将EF查询出来的 EF实体集合 转换成 Dto(Data Transfer Object)数据传输类型
List<Models.DTO.StudentDTO> list = db.Students.Include("Class").OrderBy(s => s.StudentID) .Take(pageSize).Skip((pageIndex - 1) * pageSize).ToList() .Select(s => new Models.DTO.StudentDTO() {StudentID=s.StudentID,Cid=s.Cid}).ToList(); //将EF查询出来的 EF实体集合 转换成 Dto(Data Transfer Object)数据传输类型
4.1.Select(s => new Models.DTO.StudentDTO() {StudentID=s.StudentID,Cid=s.Cid}).ToList();
//将EF查询出来的 EF实体集合 转换成 Dto(Data Transfer Object)数据传输类型
如果自己在类里面写个方法,把它转换为DTO,就不用每次写一样的这么麻烦了。所以我们在Models文件夹添加一个类
注意:
1.partial class Class
2.ClassPart.cs 返回类型是DTO.ClassDTO
3.StudentPart.cs 里面 Class = this.Class.ToDto()
这里要注意的是 StudentDTO.cs 类文件里面的 public ClassDTO Class { get; set; }
不然会报错,无法将类型“_06MVCAjax_CodeFirst.Models.DTO.ClassDTO”隐式转换为“_06MVCAjax_CodeFirst.Models.Class”
ClassPart.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace _06MVCAjax_CodeFirst.Models { public partial class Class { /// <summary> /// 将 ED的班级对象转成 DTO 的班级对象 /// </summary> /// <returns></returns> public DTO.ClassDTO ToDto() { return new DTO.ClassDTO() { Cid = this.Cid, CName = this.CName, CCount = this.CCount, CImg = this.CImg, CIsdel = this.CIsdel, Addtime = this.Addtime }; } } }
StudentPart.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace _06MVCAjax_CodeFirst.Models { public partial class Student { /// <summary> /// 将 EF Student实体转换成 DTO 学员实体 /// </summary> public DTO.StudentDTO ToDto() { return new DTO.StudentDTO() { StudentID = this.StudentID, Cid = this.Cid, Name = this.Name, Gender = this.Gender, Isdel = this.Isdel, AddTime = this.AddTime, Class = this.Class.ToDto() }; } } }
5.将数据封装到 PagedDataModel 实体
写个类PagedDataModel<T>
PagedDataModel.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace _06MVCAjax_CodeFirst.Models { /// <summary> /// 分页数据实体 /// </summary> public class PagedDataModel<T> { /// <summary> /// 封装数据 /// </summary> public List<T> PageData { get; set; } /// <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; } } }
6.将分页数据实体 封装到 json标准格式实体中
JsonModel.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace _06MVCAjax_CodeFirst.Models { /// <summary> /// Json数据实体 /// </summary> public class JsonModel { public object Data { get; set; } public string Msg { get; set; } public string Statu { get; set; } public string BackUrl { get; set; } } }
7.最后的控制器里的List方法
StuController.cs
using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Web; using System.Web.Mvc; namespace _06MVCAjax_CodeFirst.Controllers { public class StuController : Controller { // // GET: /Stu/ private Models.SingleTestContext db = new Models.SingleTestContext(); public ActionResult Index() { return View(); } //根据页码加载数据 此方法的Id其实是页码 public ActionResult List(int id) { //页码 int pageIndex = id; //页容量 int pageSize = 2; //2.1 根据页码获取分页数据 List<Models.DTO.StudentDTO> list = db.Students.Include("Class").OrderBy(s => s.StudentID) .Take(pageSize).Skip((pageIndex - 1) * pageSize).ToList() .Select(s => s.ToDto()).ToList(); //将EF查询出来的 EF实体集合 转换成 Dto(Data Transfer Object)数据传输类型 //2.2 获取总行数 int rowCount = db.Students.Count(); //2.3 计算总页数 int pageCount = Convert.ToInt32(Math.Ceiling((rowCount * 1.0) / pageSize)); //2.4 将数据封装到 PagedDataModel 实体 Models.PagedDataModel<Models.DTO.StudentDTO> dataModel = new Models.PagedDataModel<Models.DTO.StudentDTO>() { PageData = list, PageCount = pageCount, PageIndex = pageIndex, PageSize = pageSize }; //2.5 将分页数据实体 封装到 json标准格式实体中 Models.JsonModel jsonModel = new Models.JsonModel() { Data = dataModel, Msg = "成功", Statu = "OK" }; //System.Web.Script.Serialization.JavaScriptSerializer js = new System.Web.Script.Serialization.JavaScriptSerializer(); //string x = js.Serialize(jsonModel); //2.6 生成json 格式数据,Json方法是Controller类(控制器类)提供的 //JsonRequestBehavior.AllowGet 一般啊只使用post传输,如果使用get,需要设置AllowGet return Json(jsonModel, JsonRequestBehavior.AllowGet); } } }
string x = js.Serialize(jsonModel);
8.错误
8.1.get请求报错
//2.6 生成json 格式数据,Json方法是Controller类(控制器类)提供的
//JsonRequestBehavior.AllowGet 一般啊只使用post传输,如果使用get,需要设置AllowGet
return Json(jsonModel, JsonRequestBehavior.AllowGet);
8.2.查询的时候没加ToList(),不识别ToDto()方法