EF6与mvc5系列(2):实现基本的增删查改

在上节中添加控制器以后,项目中自动生成了增删改查视图。本节中我们将对其进行修改。

创建详情页

虽然项目中有Detail视图,但是我们无法查看学生的选课信息。所以修改Detail视图页如下,添加Enrollments信息。

 1 @model ContosoUniversity.Models.Student
 2
 3 @{
 4     ViewBag.Title = "Details";
 5 }
 6
 7 <h2>Details</h2>
 8
 9 <div>
10     <h4>Student</h4>
11     <hr />
12     <dl class="dl-horizontal">
13         <dt>
14             @Html.DisplayNameFor(model => model.LastName)
15         </dt>
16
17         <dd>
18             @Html.DisplayFor(model => model.LastName)
19         </dd>
20
21         <dt>
22             @Html.DisplayNameFor(model => model.FirstMidName)
23         </dt>
24
25         <dd>
26             @Html.DisplayFor(model => model.FirstMidName)
27         </dd>
28
29         <dt>
30             @Html.DisplayNameFor(model => model.EnrollmentDate)
31         </dt>
32
33         <dd>
34             @Html.DisplayFor(model => model.EnrollmentDate)
35         </dd>
36         <dt>
37             @Html.DisplayNameFor(model=>model.Enrollments);
38         </dt>
39         <dd>
40             <table class="table">
41                 <tr>
42                     <th>Course Title</th>
43                     <th>Grade</th>
44                 </tr>
45                 @foreach(var item in Model.Enrollments)
46                 {
47                     <tr>
48                         <td>
49                             @Html.DisplayFor(modelItem=>item.Course.Title)
50                         </td>
51                         <td>
52                             @Html.DisplayFor(modelItem=>item.Grade);
53                         </td>
54                     </tr>
55                 }
56             </table>
57         </dd>
58     </dl>
59 </div>
60 <p>
61     @Html.ActionLink("Edit", "Edit", new { id = Model.ID }) |
62     @Html.ActionLink("Back to List", "Index")
63 </p>

运行效果如下:

Detail页面完成。

修改创建页面

修改控制器中的Create(HttpPost)方法:添加try catch语句

        /// <summary>
        /// 通过模型绑定添加Student实体,asp.net mvc中的模型绑定将post表单
        /// 转为CLR类型,并且将其以参数的形式传递到Action方法
        /// 因为ID字段是主键,所以添加数据的时候ID字段会自动创建。不需要模型绑定
        /// </summary>
        /// <param name="student"></param>
        /// <returns></returns>
        public ActionResult Create([Bind(Include="LastName, FirstMidName, EnrollmentDate")] Student student)
        {
            try
            {                //服务器端验证,稍后将会看到客户端验证
                if (ModelState.IsValid)
                {
                    db.Students.Add(student);
                    db.SaveChanges();
                    return RedirectToAction("Index");
                }
            }
            catch (DataException)
            {
                ModelState.AddModelError("","创建失败!");
            }
            return View(student);
        }

安全提示:ValidateAntiForgeryToken属性可以防止跨站点请求伪造攻击。它需在视图中有相应的Html.AntiForgeryToken()声明,稍后将会看到。

如果Student实体包含一个Secret属性,但你不想在页面设置这个字段,即使你页面上没有这字段,黑客也可以通过工具或者写一些JavaScript传递这个字段值。如果没有模型绑定的Bind属性,黑客就可以添加Secret字段到你的实体中。你可以通过Include参数设置白名单,也可以通过Exclude设置黑名单。

另一种防止过度发布的方法就是使用视图模型而不是模型绑定的实体类。在视图模型中仅包含你想要修改的属性。

Create页面完成。

修改Edit页面的HttpPost方法

Student控制器中有两个Edit方法,这里我们只修改带有HttpPost的Edit方法。

 [HttpPost,ActionName("Edit")]
        [ValidateAntiForgeryToken]
        public ActionResult EditPost(int ?id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            var studentToUpdate = db.Students.Find(id);
            //调用TryUpdateModel方法修改用户传入的字段,EF会自动跟踪修改 Modified标志,
            if (TryUpdateModel(studentToUpdate,"",new string []{ "LastName", "FirstMidName", "EnrollmentDate"}))
            {
                try
                {
                    //调用此方法后 Modified会调用sql修改数据行,忽略并发冲突,所有的数据都会被修改,包括那些用户没有修改的
                    //稍后将会涉及如何处理并发冲突,如果你指仅修改数据库的个别字段,你可以将实体设置成Unchanged设置个别字段为Modified
                    db.SaveChanges();
                    return RedirectToAction("Index");
                }
                catch (DataException)
                {
                    ModelState.AddModelError("","修改失败");
                }
            }
            return View(studentToUpdate);
        }

因为HttpPost的Edit方法和HttpGet的Edit方法签名相同,所以修改方法名称为EditPost加以区分。目前为止,没有我们想要保护的字段,如果要防止过度发布,可以在TryUpdateModel参数中添加白名单。

实体状态,Attach和Savechanges方法

数据库上下文跟踪内存中的实体是否与其数据库的内容同步。这决定了当你调用Savechanges方法将会发生什么。例如:当你向Add方法中添加一个实体的时候,这个实体的状态就会被设置成Added,然后你调用Savechanges方法,数据库上下文就会发出一个sql的INSERT命令。

实体可能是如下状态:

Added:数据库中不攒在该实体,Savechanges方法会引发一个Insert。

UnChanged:Savechanges方法不会对该实体做任何处理,当你从数据库中读取一个实体的时候,就是以这种状态开始的。

Modified:实体的一些或者全部属性被修改后,Savechanges方法会引发一个Update声明

Deleted:实体已经被标记为删除,Savechanges方法会引发一个Delete声明。

Detached:实体未被数据上下文跟踪。

在桌面程序中,通常都是自动设置状态变化,在桌面程序中,读取实体并修改属性值,这会将实体状态自动设置成Modified,然后调用Savechanges方法,EF会生成Update语句仅修改你想修改的属性。

断开连接的web app不会发生以上这些连续序列。页面渲染以后DbContext会读取实体,调用HttpPost Edit方法时,生成一个新请求和一个新的DbContext声明。因此你必须手动设置实体状态为Modified。当调用Savechanges方法时,EF修改了数据库中的所有行,因为上下文无法知道你修改的是哪个属性。

如果你只想让sql 的update语句只修改你要修改的属性。可以用一些方法保存原始值(例如隐藏字段)。可以使用原始值创建实体并调用Attach方法。修改实体值为新值然后调用Savechanges方法。有关信息请查看:Entity states and SaveChangesLocal Data
Edit页面完成。

修改Delete页面

同前面一样,delete操作也有两个方法,Get请求的方法会展现一个视图给用户确定是否删除,如果用户删除,那么就执行Post请求。当post请求执行后才会真正删除数据。

Get请求的delete方法中,通过Find方法找到实体,这里对这个稍作修改,如果查找实体失败,给与提示用户。

在post请求的delete方法中,添加try-catch。

// GET: /Student/Delete/5/// <summary>        /// 添加可选参数设置为false,在post请求的Delete方法中会调用get方法,如果删除成功状态为true,否则为false        /// </summary>        /// <param name="id"></param>        /// <param name="saveChangesError"></param>        /// <returns></returns>
        public ActionResult Delete(int? id,bool? saveChangesError=false)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            if (saveChangesError.GetValueOrDefault())
            {
                ViewBag.ErrorMessage = "删除失败!";
            }
            Student student = db.Students.Find(id);
            if (student == null)
            {
                return HttpNotFound();
            }
            return View(student);
        }
// POST: /Student/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            try
            {
                //视图生成代码
                //Student student = db.Students.Find(id);
                //db.Students.Remove(student);
                //为了提高性能可以使用下面代码避免不需要的sql查询,这涉及到了之前讲过的实体状态
                Student studentToDelete = new Student() {ID=id };
                db.Entry(studentToDelete).State = EntityState.Deleted;
                db.SaveChanges();
            }
            catch (DataException)
            {
                return RedirectToAction("Delete", new { id = id, saveChangesError = true });
            }
            return  RedirectToAction("Index");
        }

修改视图代码,添加ViewBag

<h2>Delete</h2>
<p class="error">@ViewBag.ErrorMessage</p>
<h3>Are you sure you want to delete this?</h3>

Delete功能完成!

关闭数据库连接

关闭连接释放资源。代码提供在控制器最后提供了一个Dispose方法,基础的Controller类已经实现了IDisposable接口,因此只需重写Dispose(bool)方法销毁数据库上下文实例。

事务处理

当你修改多行数据执行Savechanges方法的时候,使用了事务。EF自动确保你所做更改要么全部成功,要么全部失败。如果先修改数据然后报错,这些修改就会自动回滚。有关事务请查看: Working with Transactions

时间: 2024-08-29 07:14:31

EF6与mvc5系列(2):实现基本的增删查改的相关文章

asp.net mvc5 step by step(一)——CURD增删查改Demo

1.  新建一个项目: 2.  在Models文件夹新增类. 代码如下: public class Product { [Key] public int Id { get; set; } public string ProductName { get; set; } public decimal Price { get; set; } public string Descript { get; set; } } 注意,这里的特性:[Key]是指定Id为主键.这里要引用 using System.

EF6与mvc5系列(1)开始

本系列教程是微软asp.net网站上的教程翻译,原文地址:http://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application . 我们将用EF6和mvc5技术完成一个应用程序Contoso University.这是一个虚拟的项目.里面包含学生管理,成绩管理,课

EF6与mvc5系列(1)

本系列教程是微软asp.net网站上的教程翻译,原文地址:http://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application   欢迎大家批评指正,共同进步. 开发工具: vs2013 .NET4.5 EF6(有关ef的版本,根据项目安装版本而定) 创建MVC应

EF6与MVC5系列(5):使用数据库迁移( Code First Migrations)和发布

本节教程包含以下内容: 启用数据库迁移(Code First Migrations):迁移特性可以改变数据模型,并且不需要删除重建数据库就可以修改数据库架构. 部署在Azure中:这步骤是可选的,可以不发布在Azure中继续学习本教程后面的内容. ps:本文中只翻译Code First Migrations相关内容,有关如何在Azure中发布,可以查看原文:https://www.asp.net/mvc/overview/getting-started/getting-started-with-

EF6与mvc5系列(3):在MVC应用程序中使用EF进行排序,过滤和分页

上节中,我们实现了基本增删查改功能,本节中要在Student的Index页面添加排序,分页和过滤功能,同时创建一个简单的分组页面. 在Student的Index页面添加列排序链接 为了在Index页面中实现排序.修改Index方法中的代码. 在Index方法中添加排序功能 修改Student控制器中的Index方法,在Index视图中添加代码. // GET: /Student/ public ActionResult Index(string sortOrder) { ViewBag.Name

[Asp.net MVC]Asp.net MVC5系列——添加模型

目录 概述 添加模型 总结 系列文章 [Asp.net MVC]Asp.net MVC5系列——第一个项目 [Asp.net MVC]Asp.net MVC5系列——添加视图 概述 在本节中我们将追加一些类来管理数据库中的学生信息.这些类将成为我们的MVC应用程序中的“模型”部分. 在vs2013中EF的版本为(Entity Framework)EF6,我们将使用EF6来进行对学生信息的维护,顺便也学习一下EF6的增删改查. 添加模型 在解决方案资源管理器中,鼠标右击Models文件夹,点击“添

[Asp.net MVC]Asp.net MVC5系列——在模型中添加验证规则

目录 概述 在模型中添加验证规则 自定义验证规则 伙伴类的使用 总结 系列文章 [Asp.net MVC]Asp.net MVC5系列——第一个项目 [Asp.net MVC]Asp.net MVC5系列——添加视图 [Asp.net MVC]Asp.net MVC5系列——添加模型 [Asp.net MVC]Asp.net MVC5系列——从控制器访问模型中的数据 [Asp.net MVC]Asp.net MVC5系列——添加数据 概述 上篇文章中介绍了添加数据,在提交表单的数据的时候,我们需

Asp.net MVC]Asp.net MVC5系列——在模型中添加

目录 概述 在模型中添加验证规则 自定义验证规则 伙伴类的使用 总结 系列文章 [Asp.net MVC]Asp.net MVC5系列--第一个项目 [Asp.net MVC]Asp.net MVC5系列--添加视图 [Asp.net MVC]Asp.net MVC5系列--添加模型 [Asp.net MVC]Asp.net MVC5系列--从控制器访问模型中的数据 [Asp.net MVC]Asp.net MVC5系列--添加数据 概述 上篇文章中介绍了添加数据,在提交表单的数据的时候,我们需

Asp.net MVC]Asp.net MVC5系列——Razor语法

目录 概念 Razor语法 总结 系列文章 [Asp.net MVC]Asp.net MVC5系列--第一个项目 [Asp.net MVC]Asp.net MVC5系列--添加视图 [Asp.net MVC]Asp.net MVC5系列--添加模型 [Asp.net MVC]Asp.net MVC5系列--从控制器访问模型中的数据 [Asp.net MVC]Asp.net MVC5系列--添加数据 [Asp.net MVC]Asp.net MVC5系列--在模型中添加验证规则 [Asp.net