[翻译][MVC 5 + EF 6] 2:基础的增删改查(CRUD)
原文:Implementing Basic CRUD Functionality with the Entity Framework in ASP.NET MVC Application
1.修改Views\Student\Details.cshtml:
@model ContosoUniversity.Models.Student
@{
ViewBag.Title = "Details";
}
<h2>Details</h2>
<div>
<h4>Student</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.LastName)
</dt>
<dd>
@Html.DisplayFor(model => model.LastName)
</dd>
<dt>
@Html.DisplayNameFor(model => model.FirstMidName)
</dt>
<dd>
@Html.DisplayFor(model => model.FirstMidName)
</dd>
<dt>
@Html.DisplayNameFor(model => model.EnrollmentDate)
</dt>
<dd>
@Html.DisplayFor(model => model.EnrollmentDate)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Enrollments)
</dt>
<dd>
<table class="table">
<tr>
<th>Course Title</th>
<th>Grade</th>
</tr>
@foreach (var item in Model.Enrollments)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Course.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.Grade)
</td>
</tr>
}
</table>
</dd>
</dl>
</div>
<p>
@Html.ActionLink("Edit", "Edit", new { id = Model.ID }) |
@Html.ActionLink("Back to List", "Index")
</p>

2.修改Controllers\StudentController.cs的Create:
[HttpPost]
[ValidateAntiForgeryToken]
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 /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
}
return View(student);
}
ValidateAntiForgeryToken属性用于防止跨站点请求伪造攻击(cross-site request forgery),在视图中需要同时添加@Html.AntiForgeryToken()来实现此功能。
Bind属性用于防止传入多余的字段。在Bind属性中Include参数列出字段白名单(whitelist),Exclude参数列出字段黑名单(blacklist)。使用Include参数会更安全,因为当我们给实体添加新字段的时候,新字段不会被自动加入黑名单。
在编辑页面,我们可以首先从数据库中读取实体然后调用TryUpdateModel,传入明确被允许的字段列表来防止传入多余的字段。
防止传入多余字段的另一种方法是使用视图模型(view model),在视图模型中只包含我们想要更新的字段。当MVC模型绑定完成后,我们可以随意使用一种工具(比如AutoMapper)将视图模型中的值拷贝到实体实例中。然后对实体实例使用db.Entry,将它的状态改为Unchanged,然后将包含在视图模型中的每个字段(Property("PropertyName").IsModified)设置为true。这种方法可以用于创建和编辑页面。
Views\Student\Create.cshtml页面的代码与Details.cshtml页面类似,不同的是EditorFor和ValidationMessageFor取代了DisplayFor:
<div class="form-group">
@Html.LabelFor(model => model.LastName, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.LastName)
@Html.ValidationMessageFor(model => model.LastName)
</div>
</div>
运行项目:

错误信息来自默认的服务端(server-side)验证:
if (ModelState.IsValid)
{
db.Students.Add(student);
db.SaveChanges();
return RedirectToAction("Index");
}
3.修改Controllers\StudentController.cs的Edit:
[HttpPost, ActionName("Edit")]
[ValidateAntiForgeryToken]
public ActionResult EditPost(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var studentToUpdate = db.Students.Find(id);
if (TryUpdateModel(studentToUpdate, "",
new string[] { "LastName", "FirstMidName", "EnrollmentDate" }))
{
try
{
db.SaveChanges();
return RedirectToAction("Index");
}
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
}
return View(studentToUpdate);
}
修改后的代码是阻止传入多余字段的最佳实践。原先的代码是脚手架自动添加的,添加了Bind属性并且为模型绑定的实体添加Modified标记,这样的代码不再被推荐,因为Bind属性会自动清理掉Include参数没有列出的字段原来的值。将来MVC脚手架将会被更新,而不再为Edit方法产生Bind属性。
修改后的代码获取已经存在的实体并根据用户输入的数据调用TryUpdateModel更新该实体。EF自动为需要跟新的实体添加Modified标记。当SaveChanges方法被调用的时候,Modified标记使EF产生Sql来更新数据库。该方法忽略了并发冲突,并且所有的列包括值没有改变的列都将会被更新(后续的教程将会展示如何处理并发冲突,如果我们如果只想更新指定的列可以设置实体为Unchanged,并且设置需要改变的列为Modified)。
数据上下文会一直跟踪内存中实体的状态是否和数据库中对应行的状态保持一致,跟踪信息将会决定当SaveChanges被调用时产生什么样的动作。例如,当我们通过Add方法添加一个实体时,这个实体的状态将会标记为Added,当调用SaveChanges放方式,数据库上下文将会调用INSERT命令。实体的状态列表:
Added:实体在数据库中还不存在,SaveChanges方法产生INSERT语句。Unchanged:SaveChanges方法将不会产生任何动作。当我们从数据库中获取一个实体时,这是该实体的初始状态。Modified:实体的部分或所有列被改变,SaveChanges方法 产生UPDATE语句。Deleted:实体被标记为删除,SaveChanges方法产生DELETE语句。Detached:该实体没有被数据库上下文跟踪。
在桌面应用程序中,实体状态的改变是自动的。在桌面性质的程序中,改变一个实体的部分字段的值,实体的状态会自动被标记为Modified。然后当我们调用时,EF将会产生只更新被改变了字段的SQL。SaveChanges
但是web应用程序的断开连接(disconnected)的性质不允许这种连续序列(continuous sequence)。当页面渲染完成后,DbContext读取的实体将会被释放掉。当HttpPost Edit被调用的时候,新的请求创建了新的DbContext实例,因此我们必须手动设置实体的状态为Modified。当调用SaveChanges时,EF将会更新所有列,数据库上下文无法知道我们更新的是哪些列。
如果我们只想要更新实际被改变的列,我们需要通过一些方式(比如隐藏域)保存原始的值,然后调用Attach方法,将实体的值更改为新值,然后调用SaveChanges。
4.修改Controllers\StudentController.cs的Delete:
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
try
{
Student student = db.Students.Find(id);
db.Students.Remove(student);
db.SaveChanges();
}
catch (DataException/* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
return RedirectToAction("Delete", new { id = id, saveChangesError = true });
}
return RedirectToAction("Index");
}
为了提升高并发程序的性能,我们需要避免不必要的查询,将上面的Find和Remove方法用下面的代码代替:
Student studentToDelete = new Student() { ID = id };
db.Entry(studentToDelete).State = EntityState.Deleted;
5.关闭数据库连接:
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
Controller基类实现了IDisposable接口,因此可以重写Dispose方法来释放上下文实例。
6.事务:
EF默认支持事务,如果同时修改多个行或者多个表并且调用SaveChanges,EF会保证这些修改同时执行成功或失败。
[翻译][MVC 5 + EF 6] 2:基础的增删改查(CRUD)的更多相关文章
- MVC3+EF4.1学习系列(二)-------基础的增删改查和持久对象的生命周期变化
上篇文章中 我们已经创建了EF4.1基于code first的例子 有了数据库 并初始化了一些数据 今天这里写基础的增删改查和持久对象的生命周期变化 学习下原文先把运行好的原图贴来上~~ 一.创建 ...
- mvc模式jsp+servel+dbutils oracle基本增删改查demo
mvc模式jsp+servel+dbutils oracle基本增删改查demo 下载地址
- mvc模式jsp+servel+jdbc oracle基本增删改查demo
mvc模式jsp+servel+jdbc oracle基本增删改查demo 下载地址
- week_one-python基础 列表 增删改查
# Author:larlly #列表增删改查#定义列表name = ["wo","ni","ta","wo"] #定义 ...
- ADO.NET基础(增删改查)
ADO.NET是一种数据访问技术,就是将C#和MSSQL连接起来的一个纽带.可以通过ADO.NET将内存中的临时数据写入到数据库中,也可以将数据库中的数据提取到内存中供程序调用. ADO.NET是所有 ...
- EF 5.0 帮助类 增删改查
原文地址:http://www.cnblogs.com/luomingui/p/3362813.html EF 5.0 帮助类 加入命名空间: using System; using System.D ...
- 使用vue+elementUI+springboot创建基础后台增删改查的管理页面--(1)
目前这家公司前端用的是vue框架,由于在之前的公司很少涉及到前端内容,对其的了解也只是会使用js和jquery,所以..慢慢来吧. 在此之前需要先了解vue的大致语法和规则,可先前往官方文档进行学习h ...
- 【ArcGIS for SivlerLight api(3)】基础图层增删改查
1.基础底图通常使用TiledLayer或者ArcGISDynamicLayer. 本质上都是在本地加载栅格图片.后台生成策略不同而已.从Vs2010的控件栏上拖过来的Map控件默认添加的底图是Esr ...
- PHP学习之[第08讲]数据库MySQL基础之增删改查
一.工具: 1.phpMyAdmin (http://www.phpmyadmin.net/) 2.Navicat (http://www.navicat.com/) 3.MySQL GUI Tool ...
随机推荐
- Spark RDD概念学习系列之RDD的容错机制(十七)
RDD的容错机制 RDD实现了基于Lineage的容错机制.RDD的转换关系,构成了compute chain,可以把这个compute chain认为是RDD之间演化的Lineage.在部分计算结果 ...
- hdoj 3861 The King’s Problem【强连通缩点建图&&最小路径覆盖】
The King’s Problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- hdoj 1898 Sempr == The Best Problem Solver?
Sempr == The Best Problem Solver? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65535/3276 ...
- 恼人的Visual Studio 2010崩溃重启问题
上周时Visual Studio 2010突然出现崩溃现象.在源文件修改只要一编译,马上就崩溃,而且还不弹出任何异常窗口,严重影响软件开发工作. google了无数解决方案 试了下面这些方法: 1)h ...
- cocos2d-x 2.0 拖尾效果分析
转自:http://game.dapps.net/gamedev/game-engine/7281.html 在Cocos2d-x中,拖尾效果有一个专门的类CCMotionStreak来实现.下面我们 ...
- [置顶] linux 解压版安装
1:下载mysql解压版包去官网下载www.mysq.com 下载.下载linux通用版本就好了 2.基本配置 首先,我们准备好Linux环境,我们使用CentOS 5.8进行试验安装.第一步,我们需 ...
- How Many Fibs_hdu_1316(大数).java
How Many Fibs? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) T ...
- Dragons
http://codeforces.com/problemset/problem/230/A Dragons time limit per test 2 seconds memory limit pe ...
- cocos2d-x jsb 防止触摸事件传递
在游戏中要实现消息弹窗,让用户点击确认,其他区域产生遮罩,阻挡下层的事件被点击到,这是个很常用的功能,在cocos2d-x中,可以通过为layer添加事件代理来实现: pDirector->ge ...
- UDF 编写自定函数
在Mysql的官方文档中有说明如何给Mysql添加新的函数. 添加的函数可分为3种: .自行编写函数的源码,将源码编译成动态库,然后使用Mysql的CREATE FUNCTION语句来将函数添加进My ...