MVC3+EF4.1学习系列(二)-------基础的增删改查和持久对象的生命周期变化

上篇文章中 我们已经创建了EF4.1基于code first的例子  有了数据库 并初始化了一些数据  今天这里写基础的增删改查和持久对象的生命周期变化

学习下原文先把运行好的原图贴来上~~

MVC3+EF4.1学习系列(二)-------基础的增删改查和持久对象的生命周期变化

MVC3+EF4.1学习系列(二)-------基础的增删改查和持久对象的生命周期变化

MVC3+EF4.1学习系列(二)-------基础的增删改查和持久对象的生命周期变化

MVC3+EF4.1学习系列(二)-------基础的增删改查和持久对象的生命周期变化

一.创建详细页

首先 我们先在控制器下 添加详细页的方法

因为这篇文章后面要介绍持久对象声明周期的变化 所以在这里先看下有哪些状态

MVC3+EF4.1学习系列(二)-------基础的增删改查和持久对象的生命周期变化

EF里一共有这五中生命状态类型 其实 看名字我们可以大概猜测出个一二三来~~  游离的 未改变的  新添加的  已删除的 修改的  但是是怎么变化的能

我们在后面的代码中实践与证实

复制代码

    public ActionResult Details(int id)
       {
   
          Student student
= db.Students.Find(id);
          EntityState statebefore
= db.Entry(student).State; //通过find取出来得到的状态是  Unchanged
           return View(student);
       }

复制代码

通过调试 我们可以看到 通过find取出来得到的状态是  Unchanged  没有变化的~~

这里面 我们用到了 db.Entry()方法 这个方法是很不错的  不仅可以看状态 还可以跟踪到OriginalValue(原始值),CurrentValue(当前值)和DatabaseValue(数据库值)

看到园子里已经有介绍这个的了 而且写的非常好~~ 这里直接把连接给大家 大家自己去看吧  文章连接

接着回到我们的项目~现在开始添加视图

复制代码

@model ContosoUniversity.Models.Student

@{
   ViewBag.Title = "Details";
   Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Details</h2>

<fieldset>
   
<legend>Student</legend>

   
<div class="display-label">LastName</div>
   
<div class="display-field">@Model.LastName</div>

   
<div class="display-label">FirstMidName</div>
   
<div class="display-field">@Model.FirstMidName</div>

   
<div class="display-label">EnrollmentDate</div>
   
<div class="display-field">@String.Format("{0:g}", Model.EnrollmentDate)</div>


   
<div class="display-field">
   
<table>
       
<tr>
           
<th>Course Title</th>
           
<th>Grade</th>
       
</tr>
       @foreach (var item in Model.Enrollments)
       {
           
<tr>
             
<td>@item.Course.Title</td>
             
<td>@item.Grade</td>
           
</tr>
       }
   
</table>
</div>


</fieldset>
<p>
   @Html.ActionLink("Edit", "Edit", new { id=Model.StudentID }) |
   @Html.ActionLink("Back to List", "Index")
</p>

复制代码

这里面  我们不仅显示了该学生的详细信息  还显示了该学生选择的课程和成绩

因为我们的学生实体 有导航属性 Enrollments  这里面 遍历每一个Enrollments 来Enrollment  来得到分数  由于我们的Enrollment 实体 包含了课程实体的导航属性 所以可以得到

 课程的名字  

这里面 涉及到了延迟加载  等读取相关属性的多关系数据的加载 这个不是我们这节讨论的重点 这个会在第五节讨论  到时会把加载的方式 生成的sql语句 等 讲清楚的 放心吧~~

在这里暂时就先不说了 直接开始下面的创建页

二.创建添加页面

首先 依然是添加控制器下的方法  这里面的方法要记得是 HttpPost Create   不加post  就是get的方式 是直接访问页面时用的  post提交时用

其次 我们依然来看下这次生命周期状态的改变

复制代码

      [HttpPost]
       
public ActionResult Create(Student student)
       {
           
try
           {
               
// TODO: Add insert logic here
               if (ModelState.IsValid)
               {
                   EntityState statebefore
= db.Entry(student).State;  //Detached
                   db.Students.Add(student);
                   EntityState stateAdd
= db.Entry(student).State; //Added
                   db.SaveChanges();
                   EntityState stateafter
= db.Entry(student).State;//Unchanged
                   return RedirectToAction("Index");
               }
           }
           
catch
           {
               ModelState.AddModelError(
"", "Unable to save changes. Try again, and if the problem persists see your system administrator.");

           
           }
           
return View(student);
       }

复制代码

先说个MVC的问题 这里面 我们可以直接把参数换成Create(Student student) 也可以使用FormCollection 来获得一个个值  但是推荐使用第一种方式~~

这里面的原理是 路由过来的或者参数过来的,会自动地赋值到对象的对应的属性上  做这个工作的就是实现了 IModelBinder 接口的

有兴趣的可以去google下~~ 这里主讲EF MVC的东西顺带提下~

回到例子 我们可以看到 生命周期的变化  Detached--->Added---->Unchanged

添加视图

复制代码

@model ContosoUniversity.Models.Student

@{
   ViewBag.Title = "Create";
   Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Create</h2>

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@using (Html.BeginForm()) {
   @Html.ValidationSummary(true)
   
<fieldset>
       
<legend>Student</legend>

       
<div class="editor-label">
           @Html.LabelFor(model => model.LastName)
       
</div>
       
<div class="editor-field">
           @Html.EditorFor(model => model.LastName)
           @Html.ValidationMessageFor(model => model.LastName)
       
</div>

       
<div class="editor-label">
           @Html.LabelFor(model => model.FirstMidName)
       
</div>
       
<div class="editor-field">
           @Html.EditorFor(model => model.FirstMidName)
           @Html.ValidationMessageFor(model => model.FirstMidName)
       
</div>

       
<div class="editor-label">
           @Html.LabelFor(model => model.EnrollmentDate)
       
</div>
       
<div class="editor-field">
           @Html.EditorFor(model => model.EnrollmentDate)
           @Html.ValidationMessageFor(model => model.EnrollmentDate)
       
</div>

       
<p>
           
<input type="submit" value="Create" />
       
</p>
   
</fieldset>
}

<div>
   @Html.ActionLink("Back to List", "Index")
</div>

复制代码

这里面我们选择开启验证  MVC验证会先验证客户端 再验证服务端 我们可以验证的有 是否为空 最大长度 最小长度  格式 比较是否相等等

这里 我们只需要在 实体上添加特性 MaxLength 等特性 

这里我这有所有可以添加的特性的收集和介绍   大家可以看这个连接文章-----DataAnnotation验证

然后运行 发现当添加数据不符合要求时 会先进行js验证 提示错误 OK 添加就到这里

三.创建编辑页面

复制代码

  public ActionResult Edit(int id)
       {
           Student student
= db.Students.Find(id);
           
return View(student);
       }

       
//
       
// POST: /Student/Edit/5

       [HttpPost]
       
public ActionResult Edit(Student student)
       {
               
// TODO: Add update logic here
               if (ModelState.IsValid)
               {
                   EntityState statebefore
= db.Entry(student).State;  
                   db.Entry(student).State
= EntityState.Modified;
                   
int i= db.SaveChanges();
                   EntityState stateafter
= db.Entry(student).State;
                   
return RedirectToAction("Index");
               }
           
return View(student);
       }

复制代码

EF里的更新是这样的  通过更改 状态为EntityState.Modified 然后再保存 来实现更新操作的

我们可以看到 生命周期的变化  Detached--->Modified---->Unchanged

添加视图

复制代码

@model ContosoUniversity.Models.Student

@{
   ViewBag.Title = "Edit";
   Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Edit</h2>

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@using (Html.BeginForm()) {
   @Html.ValidationSummary(true)
   
<fieldset>
       
<legend>Student</legend>

       @Html.HiddenFor(model => model.StudentID)

       
<div class="editor-label">
           @Html.LabelFor(model => model.LastName)
       
</div>
       
<div class="editor-field">
           @Html.EditorFor(model => model.LastName)
           @Html.ValidationMessageFor(model => model.LastName)
       
</div>

       
<div class="editor-label">
           @Html.LabelFor(model => model.FirstMidName)
       
</div>
       
<div class="editor-field">
           @Html.EditorFor(model => model.FirstMidName)
           @Html.ValidationMessageFor(model => model.FirstMidName)
       
</div>

       
<div class="editor-label">
           @Html.LabelFor(model => model.EnrollmentDate)
       
</div>
       
<div class="editor-field">
           @Html.EditorFor(model => model.EnrollmentDate)
           @Html.ValidationMessageFor(model => model.EnrollmentDate)
       
</div>

       
<p>
           
<input type="submit" value="Save" />
       
</p>
   
</fieldset>
}

<div>
   @Html.ActionLink("Back to List", "Index")
</div>

复制代码

四.创建删除页面

复制代码

        public ActionResult Delete(int id, bool? saveChangesError)
       {
           
if (saveChangesError.GetValueOrDefault())
           {
               ViewBag.ErrorMessage
= "Unable to save changes. Try again, and if the problem persists see your system administrator.";
           }
           
return View(db.Students.Find(id));
       }

       
//
       
// POST: /Student/Delete/5

       [HttpPost,ActionName(
"Delete")]
       
public ActionResult DeleteConfirmed(int id)
       {
           
try
           {
               
// TODO: Add delete logic here
               Student student = db.Students.Find(id);
               EntityState statebefore
= db.Entry(student).State; //UnChange状态
               db.Students.Remove(student);
               EntityState stateafter
= db.Entry(student).State;//Deleted状态
               db.SaveChanges();
               EntityState stateaOk
= db.Entry(student).State;//Detached状态
               return RedirectToAction("Index");
           }
           
catch
           {
               
return View();
           }
       }

复制代码

复制代码

@model ContosoUniversity.Models.Student

@{
   ViewBag.Title = "Delete";
   Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Delete</h2>

<h3>Are you sure you want to delete this?</h3>
<fieldset>
   
<legend>Student</legend>

   
<div class="display-label">LastName</div>
   
<div class="display-field">@Model.LastName</div>

   
<div class="display-label">FirstMidName</div>
   
<div class="display-field">@Model.FirstMidName</div>

   
<div class="display-label">EnrollmentDate</div>
   
<div class="display-field">@String.Format("{0:g}", Model.EnrollmentDate)</div>
</fieldset>
@using (Html.BeginForm()) {
   
<p>
       
<input type="submit" value="Delete" /> |
       @Html.ActionLink("Back to List", "Index")
   
</p>
}

复制代码

这样就实现了删除了   这是原文博客里的方法  但我觉得很不合理 

点击删除还要跳到专门的删除页  然后删除完再跳回来  这里 我们使用ajax来改造删除  来减少来回的跳页等的交互 以提高效率 (主要点写写MVC的应用了~~)

五.AJAX改造删除

我这里是用的 jquery ajax 用的习惯些~~

先改造控制器下的方法

主要是加上 if (Request.IsAjaxRequest()) 判断是否为ajax   接着 把返回类型改为 Content 返回-1 为修改失败 代码如下

复制代码

   [HttpPost,ActionName("Delete")]
       
public ActionResult DeleteConfirmed(int id)
       {
           
try
           {
               
// TODO: Add delete logic here

               
if (Request.IsAjaxRequest())
               {
                   Student student
= db.Students.Find(id);
                   db.Students.Remove(student);
                   EntityState stateafter
= db.Entry(student).State;//Deleted状态
                   int result = db.SaveChanges();
                   
return Content(result.ToString());
               }
               
else
               {
                   
return Content("-1");
               }
           }
           
catch
           {
               
return Content("-1");
           }
       }

复制代码

接着是修改视图部分

首先 把原来的删除换成这句

     <a  name="Delete" stuid="@item.StudentID">Delete</a>

然后引用jquery 接着 实现删除~~

复制代码

    $(function () {
       $(
"[name='Delete']").click(
       
function () {
           
if (confirm("确定要删除这条记录么?")) {
               
var stuid = $(this).attr("stuid");
               
var tr = $(this).parent().parent();

               $.post(
"Student/Delete/", { id: stuid }, function (data) {
                   
if (data == "-1") {
                       alert(
"删除失败");
                   }
                   
else {
                       $(tr).remove();
                       alert(
"删除成功");
                   }

               });
           }
       }
       );
   });

复制代码

OK了 改造成功~~

六.确保数据库资源及时释放

原文里面最要提出 让Controller类继承 IDisposable接口 以确保资源的即使释放  这里我理解的还不是很深刻有兴趣的可以看下原文 但我把代码贴出来

protected override void Dispose(bool disposing)
{
   db.Dispose();
   
base.Dispose(disposing);
}

七.总结

好了,简单的增删改查结束了 依然是没有多大难度的文章 新手可以看下 学习下EF的使用 

这里面主要讲了 基本的CRUD和 这里面持久属性的状态的变化 并在后面用ajax重新实现了次删除
明天写 

排序 刷选 分页---- (这里我用的是国产的基于ScottGu的PagedList<T>类和相关方法完善的分页--MVCPager)

也是比较简单的 但至少更加贴近实际项目了~~


你可能感兴趣的:(mvc,C#)