Contoso 大学 2 – 实现基本的增删改查

目录

Contoso 大学 - 使用 EF Code First 创建 MVC 应用

原文地址:http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-basic-crud-functionality-with-the-entity-framework-in-asp-net-mvc-application

在上一个课程中,你已经创建了 MVC 应用,使用 EF 和 SQL Server Compact 保存和显示数据。在这个课程中,你将要复习并定制 MVC 脚手架为你的控制器和视图自动创建的 CRUD (创建、读取、更新和删除)代码。注意:为了在你的控制器和数据访问层之间进行抽象,通常的做法是实现仓储模式。为了保持这个课程的简洁,在这个系列的最后课程之前,我们不会实现仓储模式。

在这个课程中,你将要创建如下的页面。

2-1 创建详细页

脚手架创建的代码遗留下了学生注册属性没有处理,因为这个属性是集合属性。在详细页面中,你将要在 HTML 表格中显示这个集合的内容。

在 Controllers\StudentController.cs 中,详细页面的 Action 方法类似如下的代码:

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

代码使用 Find 方法来获取单个的 Student 实体,使用传递给方法的 id 关键字。Id 来自 Index 页面中的超级链接提供的查询字符串。

打开 Views\Student\Details.cshtml。每个字段使用 DisplayFor 助手方法进行显示,类似如下所示:

<div class="display-label">LastName</div>
<div class="display-field">
@Html.DisplayFor(model => model.LastName)
</div>

为了显示注册课程列表,在注册日期 EnrollmentDate 字段之后,fieldset 结束标记之前,增加如下的代码。

<div class="display-label">
@Html.LabelFor(model => model.Enrollments)
</div>
<div class="display-field">
<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>
</div>

代码遍历导航属性 Enrollments 中所有的实体,对于这个属性中的每一个 Enrollment 实体,将显示其中的课程和年级。课程标题通过 Enrollments  导航属性保存的 Course  实体来获得。在需要的时候,所有的数据从数据库中获取。( 从另外一个角度说,在这里使用了延迟加载,你没有为 Courses 导航属性指定饿汉模式加载,所以,在你第一次试图访问这个属性的时候,将会向数据库发出一次查询来获取数据,你可以在这个系列后面的 读取相关数据 部分获取更加详细的说明 )

运行这个页面,选择 Students 选项卡,然后点击 Details 超级链接,你就可以看到课程的列表。

2-2 建立创建页面

在 Controllers\StudentController.cs使用下面的代码替换HttpPostCreate 这个 Action 方法,为脚手架创建的代码增加 try-catch 块。

[HttpPost]
public ActionResult Create(Student student)
{
try
{
if (ModelState.IsValid)
{
db.Students.Add(student);
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch (DataException)
{
//Log the error (add a variable name after DataException)
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
}
return View(student);
}

这些代码将通过 ASP.NET MVC 模型绑定创建的实体对象加入到 Students 集合中,然后保存修改到数据库中。( 模型绑定是 ASP.NET MVC 的一个功能用于简化你获取通过表单提交的数据,模型绑定转换提交的表单数据到 .NET 中的数据类型,通过 Action 方法的参数传递进来,在这里,模型绑定通过表单数据为你实例化了一个 Student 的实体对象实例 ) 

这里的 try-catch 块是这些代码区别于脚手架创建的代码的唯一不同之处,在保存数据的时候,如果派生自DataException 的异常被抛出,错误信息将会被显示出来,这类错误典型的是由于一些内部错误,而不是程序错误,所以建议用户再重新试一次。在 Views\Student\Create.cshtml 中的代码与 Details.cshtml 中类似,除了将每个字段的 DisplayFor 代替为EditorFor 和 ValidationMessageFor 助手方法.下面的示例演示了相关的代码。

<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>

 Create.cshtml. 中不需要进行修改。

重新运行页面,选择 Students选项卡,点击 Create New

默认会进行数据验证,输入名字和一个错误的日期,然后点击 Create,查看一下错误提示。

现在,你会看到通过 JavaScript 实现的客户端验证,但是,服务器端的验证也已经实现了。即使客户端验证失败了,坏的数据也会被捕获到,在服务器端会抛出一个异常。

将日期修改为一个正确的日期,例如:9/1/2005,然后点击 Create,会看到一个新的学生出现在 Index页面上。

2-3 创建一个编辑页面

在 Controllers\StudentController.cs 中,Http Edit 方法 ( 其中没有使用 HttpPost标签的那一个 ) 使用 Find 方法来获取选中的学生实体,像你在 Details 方法中看到的一样,不需要修改这个方法。

实际上,需要修改 HttpPost Edit 方法,使用下面的代码为它增加 try-catch处理。

[HttpPost]
public ActionResult Edit(Student student)
{
try
{
if (ModelState.IsValid)
{
db.Entry(student).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch (DataException)
{
//Log the error (add a variable name after DataException)
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
}
return View(student);
}

这段代码非常类似在 Create 中的代码,实际上,除了将通过模型绑定创建的对象添加到实体集中,这段代码还设置了实体的标志来表示这个实体已经被修改过了。当SaveChanges方法被调用的时候,数据库中行的所有字段都将会更新。包括用户没有修改过的字段,并发冲突被忽略掉 ( 你将会在这个系列的后面学习如何处理并发问题 )。

实体的状态,连接以及 SaveChanges 方法

数据库上下文对象维护内存中的对象与数据库中数据行之间的同步。这些信息在调用 SaveChanges方法被调用的时候使用。例如,当使用 Add 方法传递一个新的实体对象时,实体的状态被设置为 Added,在调用 SaveChanges方法的时候,数据库上下文使用 SQL 命令 Insert来插入数据。

实体的状态可能为如下之一:

  1.  Added. 实体在数据库中不存在。SaveChanges 方法必须执行 Insert 命令
  2.  Unchanged. 在调用 SaveChanges 的时候不需要做任何事情,当从数据库读取数据的时候,实体处于此状态。
  3.  Modified. 某些或者全部的实体属性被修改过. SaveChanges方法需要执行 Update 命令。

 Deleted. 实体标记为已删除,SaveChanges 方法必须执行 Delete 命令。

 Detached. 实体的状态没有被数据库上下文管理。

在桌面应用中,实体的状态改变典型地自动完成。在这种类型的应用中,你读取一个实体,然后修改某些属性的值,这使得实体的状态被自动修改为 Modified。然后,在调用SaveChanged 的时候,实体框架生成 Update 命令进行更新,只有你修改的实际属性被更新。

但是,在 Web 应用程序中,这个处理序列不是连续的。因为数据库上下文读取的实体对象实例在页面被呈现之后被丢弃了。当 HttpPost Edit 方法被调用的时候,导致一个新的请求和一个新的数据库上下文对象被生成,所以,你必须手工设置实体的状态为 Modified。然后调用 SaveChanges 方法,实体框架更新数据库中数据行的所有列,因为数据库上下文没有办法知道你修改了哪些属性。

如果你希望 Update 语句仅仅更新你实际上修改的字段。你可以通过某种途径保存原有的数据值 ( 例如通过隐藏域 ),以便在 HttpPost Edit 方法被调用的时候这些值存在。然后,可以使用原始的数据来创建一个 Student 实体,使用 Attach 方法调用连接含有原始值的实体对象,然后,使用新的值来更新实体对象,最后再调用 SaveChanges 方法,更多的详细内容,可以查看 EF 团队的博客: Add/Attach and Entity StatesLocal Data

在 Views\Student\Edit.cshtml中的代码类似于 Create.cshtml ,不需要修改。

运行页面,选择 Students 选项卡,然后点击 Edit 超级链接。

修改一些数据,然后点击 Save,可以在 Index 页面看到修改后的数据。

2-4  创建删除页面

 Controllers\StudentController.cs, 模板生成的 HttpGet Delete 方法使用 Find 方法来获取 Student 实体,像在Details 和 Edit 方法中一样。实际上,为了实现在调用SaveChanges 方法失败的时候使用的错误页面,你需要为这个方法和相应的视图增加一些功能。

像在更新和创建操作中一样,删除操作也需要两个方法。GET 方法用于显示一个视图,使用户可以允许或者取消删除操作,如果用户允许删除操作,那么,将会发出一个Post 请求,HttpPost Delete 方法将会被调用,然后执行实际的删除操作。

你需要为 HttpPost Delete 方法增加一个 try-catch 块来捕获数据库更新过程中的任何异常。如果错误出现,HttpPost Delete 方法调用 HttpGet Delete 方法,传递一个参数表示错误发生了。HttpGet Delete 方法就会根据错误信息重新显示确认页面,使用户可以取消或者重试。

使用下面的代码替换 HttpGet Delete 方法中的代码,这里会管理错误报告。

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));
}

这段代码接收一个可选的 bool 类型参数,这个参数用来表示是在更新失败之后调用这个方法。在页面请求中被调用的时候,这个参数为 null ( false ),当通过 HttpPost Delete方法更新数据库失败后,被调用的时候,参数被设置为 true,错误信息被传递到视图中。

将 HttpPost Delete 方法 ( 名为 DeleteConfirmed 方法 )的代码替换成下面的代码,这将会执行实际的删除操作,并捕获任何数据库更新错误。

[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
try
{
Student student = db.Students.Find(id);
db.Students.Remove(student);
db.SaveChanges();
}
catch (DataException)
{
//Log the error (add a variable name after DataException)
return RedirectToAction("Delete",
new System.Web.Routing.RouteValueDictionary {
{ "id", id },
{ "saveChangesError", true } });
}
return RedirectToAction("Index");
}

这段代码获取选中的实体,然后调用 Remove 方法将实体的状态设置为 Deleted。当调用 SaveChanged 的时候,SQL 命令 Delete 被生成并执行。

如果性能是应用的高优先级目标,你可以省略掉不需要的 SQL 查询处理,使用下面的代码行调用 Find 和 Remove 方法。

Student studentToDelete = new Student() { StudentID = id };
db.Entry(studentToDelete).State = EntityState.Deleted;

这段代码实例化了一个 Student 实体,仅仅设置了主键的值,然后将实体的状态设置为 Deleted。EF 删除实体仅仅需要这些信息。

需要注意的是,HttpGet Delete 方法并不真正删除数据,在 GET 请求处理中进行删除存在着安全风险 ( 同样在进行编辑,创建,或者任何修改数据的处理中 ),更多的资料,参见:ASP.NET MVC Tip #46 — Don't use Delete Links because they create Security Holes

在 Views\Student\Delete.cshtml 中,在 h2 和 h3 之间增加下面的代码:

<p class="error">@ViewBag.ErrorMessage</p>

运行页面,选择 Students 选项卡,点击 Delete 超级链接。

点击 Delete,Index 页面中就不会再显示被删除的学生了。( 在处理并发的部分可以看到错误处理 )

2-5  确认数据库连接没有忘记关闭

为了确认数据库连接被正确关闭,以及资源被正确释放,你需要释放数据库上下文,这就是为什么在 StudentController 代码的最后会看到 Dispose 方法的原因,在StudentController.cs, 如下所示:

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

基类 Controller 已经实现了接口 IDisposable,所以这段代码简单地重写了 Dispose ( bool ) 方法来显式释放上下文对象。

你现在已经有了一套完整的页面对 Student 进行增、删、改、查处理。在下一课程中,将会为 Index 页面增加排序和分页功能。

 

EF

翻译:Contoso 大学 - 3 - 排序、过滤及分页
摘要: 目录Contoso 大学 - 使用 EF Code First 创建 MVC 应用原文地址:http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/sorting-filtering-and-paging-with-the-entity-framework-in-an-asp-net-mvc-application在上一个课程中,我们已经学习了如何使用 EF 对 Student 实体进行增、删、改、查处理。这次的课程我们将对学生的 Index 页面加入排序、过滤以及分页的功能。还要创建一个页面完成简单的分组。下面的截阅读全文

posted @ 2012-04-08 22:48 冠军 阅读(43) | 评论 (0) 编辑

Contoso 大学 - 2 – 实现基本的增删改查
摘要: 目录Contoso 大学 - 使用 EF Code First 创建 MVC 应用原文地址:http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-basic-crud-functionality-with-the-entity-framework-in-asp-net-mvc-application在上一个课程中,你已经创建了 MVC 应用,使用 EF 和 SQL Server Compact 保存和显示数据。在这个课程中,你将要复习并定制 MVC 脚手架为你的控制器和视图自动创建的 CR阅读全文

posted @ 2012-04-07 17:11 冠军 阅读(712) | 评论 (3) 编辑

Contoso 大学 - 1 - 为 ASP.NET MVC 应用程序创建 EF 数据模型
摘要: 原文地址:Creating an Entity Framework Data Model for an ASP.NET MVC Application (1 of 10)Contoso 大学 Web 示例应用演示了如何使用 EF 技术创建 ASP.NET MVC 应用。示例中的 Contoso 大学是虚构的。应用包括了类似学生注册、课程创建以及教师分配等功能。这个系列教程展示了创建 Contoso 大学应用的步骤。你可以 下载完整 的程序,或者按照教程一步一步创建它,这个教程中使用 C# 进行演示,下载的代码中同时包含 C# 和 VB 实现。如果你有与这个教程没有直接相关的问题,可以张贴到 A阅读全文

posted @ 2012-04-04 14:05 冠军 阅读(1128) | 评论 (5) 编辑

Contoso 大学 - 使用 EF Code First 创建 MVC 应用
摘要: Contoso 大学 Web 示例应用演示了如何使用 EF 技术创建 ASP.NET MVC 应用。示例中的 Contoso 大学是虚构的。应用包括了类似学生注册、课程创建以及教师分配等功能。这个系列教程展示了创建 Contoso 大学应用的步骤。你可以 下载完整 的程序,或者按照教程一步一步创建它,这个教程中使用 C# 进行演示,下载的代码中同时包含 C# 和 VB 实现。如果你有与这个教程没有直接相关的问题,可以张贴到 ASP.NET Entity Framework forum 或者 Entity Framework and LINQ to Entities forum.这个教程假设你知阅读全文

posted @ 2012-04-04 14:04 冠军 阅读(1223) | 评论 (5) 编辑

EF4.3 基于代码的迁移演练
摘要: 原文地址:http://blogs.msdn.com/b/adonet/archive/2012/02/09/ef-4-3-code-based-migrations-walkthrough.aspx原文名称:EF 4.3 Code-Based Migrations Walkthrough准备工作在开始之前,我们需要一个项目,以及一个 Code First 的模型,对于这次演示,我们使用典型的博客 Blog 和回复 Post 模型。1. 创建新的 MigrationsCodeDemo 控制台应用程序2. 为项目添加最新版本的 EntityFramework NuGet 包。找到包管理器控制台。阅读全文

posted @ 2012-02-17 22:59 冠军 阅读(1813) | 评论 (7) 编辑

EF 4.3 发布
摘要: 原文名称:EF 4.3 Released原文地址:http://blogs.msdn.com/b/adonet/archive/2012/02/09/ef-4-3-released.aspxEF 4.3 下载地址:http://nuget.org/packages/EntityFramework/在过去的六个月中,我们发布了有关 Code First 迁移的一系列预览,今天,我们将迁移作为 EF4.3 的一部分进行完整的发布。在 EF 4.2 与 4.3 之间的变化:新的 Code First 迁移特性:这是 EF 4.3 中主要的新特性,允许通过 Code First 创建的数据库可以与你的阅读全文

posted @ 2012-02-14 22:58 冠军 阅读(794) | 评论 (2) 编辑

Entity Framework 4.1 之八:绕过 EF 查询映射
摘要: 原文名称:Entity Framework 4.1: Bypassing EF query mapping(8)原文地址:http://vincentlauzon.wordpress.com/2011/04/21/entity-framework-4-1-bypassing-ef-query-mapping-8/看到 Entity Framework 4.1 推荐英文教程,为了帮大家看起来方便一些,简单翻译一下。这是一个系列,共有 8 篇,这是第8 篇。Entity Framework 4.1 之一 : 基础Entity Framework 4.1 之二 : 覆盖默认的约定Entity Fra阅读全文

posted @ 2011-05-09 10:59 冠军 阅读(5720) | 评论 (5) 编辑

Entity Framework 4.1 之七:继承
摘要: 原文名称:Entity Framework 4.1: Inheritance(7)原文地址:http://vincentlauzon.wordpress.com/2011/04/19/entity-framework-4-1-inheritance-7/看到 Entity Framework 4.1 推荐英文教程,为了帮大家看起来方便一些,简单翻译一下。这是一个系列,共有 8 篇,这是第7 篇。Entity Framework 4.1 之一 : 基础Entity Framework 4.1 之二 : 覆盖默认的约定Entity Framework 4.1 之三 : 贪婪加载和延迟加载Entit阅读全文

posted @ 2011-05-08 21:47 冠军 阅读(4166) | 评论 (2) 编辑

Entity Framework 4.1 之六:乐观并发
摘要: 原文名称:Entity Framework 4.1: Optimistic Concurrency(6)原文地址:http://vincentlauzon.wordpress.com/2011/04/17/entity-framework-4-1-optimistic-concurrency-6/看到 Entity Framework 4.1 推荐英文教程,为了帮大家看起来方便一些,简单翻译一下。这是一个系列,共有 8 篇,这是第8 篇。Entity Framework 4.1 之一 : 基础 Entity Framework 4.1 之二 : 覆盖默认的约定 Entity Framework阅读全文

posted @ 2011-05-08 12:30 冠军 阅读(4579) | 评论 (6) 编辑

Entity Framework 4.1 之五:多对多的关系
摘要: 原文名称:Entity Framework 4.1: Many to Many Relationships(5)原文地址:http://vincentlauzon.wordpress.com/2011/04/15/entity-framework-4-1-many-to-many-relationships-5/看到 Entity Framework 4.1 推荐英文教程,为了帮大家看起来方便一些,简单翻译一下。这是一个系列,共有 8 篇,这是第5 篇。Entity Framework 4.1 之一 : 基础Entity Framework 4.1 之二 : 覆盖默认的约定Entity Fra阅读全文

posted @ 2011-05-08 09:17 冠军 阅读(5442) | 评论 (18) 编辑

Entity Framework 4.1 之四:复杂类型
摘要: 原文名称:Entity Framework 4.1: Complex Types(4)原文地址:http://vincentlauzon.wordpress.com/2011/04/13/entity-framework-4-1-complex-types-4/看到 Entity Framework 4.1 推荐英文教程,为了帮大家看起来方便一些,简单翻译一下。这是一个系列,共有 8 篇,这是第4 篇。Entity Framework 4.1 之一 : 基础Entity Framework 4.1 之二 : 覆盖默认的约定Entity Framework 4.1 之三 : 贪婪加载和延迟加载E阅读全文

posted @ 2011-05-07 23:16 冠军 阅读(4710) | 评论 (12) 编辑

Entity Framework 4.1 之三 : 贪婪加载和延迟加载
摘要: 原文名称:Entity Framework 4.1: Deep Fetch vs Lazy Load(3)原文地址:http://vincentlauzon.wordpress.com/2011/04/11/entity-framework-4-1-deep-fetch-vs-lazy-load-3/看到 Entity Framework 4.1 推荐英文教程,为了帮大家看起来方便一些,简单翻译一下。这是一个系列,共有 8 篇,这是第3 篇。Entity Framework 4.1 之一 : 基础 Entity Framework 4.1 之二 : 覆盖默认的约定 Entity Framewo阅读全文

posted @ 2011-05-07 10:20 冠军 阅读(6859) | 评论 (10) 编辑

Entity Framework 4.1 之二 : 覆盖默认的约定
摘要: 原文名称:Entity Framework 4.1: Override conventions (2)原文地址:http://vincentlauzon.wordpress.com/2011/04/06/entity-framework-4-1-override-conventions-2/看到 Entity Framework 4.1 推荐英文教程,为了帮大家看起来方便一些,简单翻译一下。这是一个系列,共有 8 篇,这是第2 篇。Entity Framework 4.1 之一 : 基础 Entity Framework 4.1 之二 : 覆盖默认的约定 Entity Framework 4.阅读全文

posted @ 2011-05-06 17:12 冠军 阅读(8118) | 评论 (17) 编辑

Entity Framework 4.1 之一 : 基础
摘要: 原文名称:Entity Framework 4.1: Basics (1)原文地址:http://vincentlauzon.wordpress.com/2011/04/03/entity-framework-4-1-basics-1/看到 Entity Framework 4.1 推荐英文教程,为了帮大家看起来方便一些,简单翻译一下。这是一个系列,共有 8 篇,这是第1 篇。Entity Framework 4.1 之一 : 基础Entity Framework 4.1 之二 : 覆盖默认的约定Entity Framework 4.1 之三 : 贪婪加载和延迟加载Entity Framewo阅读全文

posted @ 2011-05-06 15:01 冠军 阅读(13647) | 评论 (13) 编辑

原文地址:https://www.cnblogs.com/Leo_wl/p/2438243.html