EntityFramework_MVC4中EF5 新手入门教程之二 ---2.执行基本的 CRUD 功能-程序员宅基地

在前面的教程中,您创建 MVC 应用程序中,存储和显示数据使用实体框架和 SQL 服务器 LocalDB。在本教程中,您会审查和自定义的 CRUD (创建、 读取、 更新、 删除) MVC 脚手架会自动为您在控制器和视图中创建的代码。

它是常见的做法,实施资源库模式,以创建您的控制器和数据访问层之间的一个抽象层。为了保持这些教程简单,不会直到后来在这个系列教程执行一个存储库。

在本教程中,您将创建以下 web 页:

Student_Details_page

Student_Edit_page

Student_Create_page

 

Student_delete_page

创建详细信息页

学生Index 页的搭建的代码排除在外的Enrollments属性,因为该属性包含一个集合。Details 页中,您将显示在 HTML 表中的集合的内容。

Controllers\StudentController.csDetails视图的操作方法使用 Find方法检索单个Student实体。

public ActionResult Details(int id = 0) {
                  Student student = db.Students.Find(id); if (student == null) {
                                         return HttpNotFound(); } return View(student); }

注册表项值将传递给作为id参数方法和索引页上来自路网数据的Details的超链接。

  1. 打开Views\Student\Details.cshtml每个字段显示使用的DisplayFor的帮手,如下面的示例所示:
        <div class="display-label"> @Html.DisplayNameFor(model => model.LastName) </div> <div class="display-field"> @Html.DisplayFor(model => model.LastName) </div>
  2. 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> </fieldset> <p> @Html.ActionLink("Edit", "Edit", new { id=Model.StudentID }) | @Html.ActionLink("Back to List", "Index") </p>

    此代码将遍历中Enrollments导航属性的实体。对于每个Enrollment实体的属性中,它显示课程标题和品位。从存储在Enrollments实体的Course导航属性的Course实体检索课程标题。所有这些数据是从数据库中检索自动当需要它时。(也就是说,您正在使用延迟加载在这里。您没有指定预先加载Courses导航属性,所以第一次尝试访问该属性,查询被发送到数据库以检索数据。你可以阅读更多关于延迟加载和读取相关数据教程稍后在本系列中的预先加载。)

  3. 通过选择Students选项卡并单击一个Details链接为Alexander Carson运行该页。您为所选的学生看到课程和成绩的列表:

    Student_Details_page

更新创建页

  1. Controllers\StudentController.cs,用下面的代码将try-catch块和绑定属性添加到搭建方法替换HttpPostCreate操作方法:
    [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 after DataException 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); }

    此代码将添加创建的 ASP.NET MVC 模型联编程序对Students主体性的Student实体集,然后将更改保存到数据库。(指容易你一起提交的表单数据的 ASP.NET MVC 功能的模型联编程序; 模型联编程序将已发布的窗体值转换为 CLR 类型,并将它们传递给操作方法的参数。在这种情况下,模型联编程序实例化一个Student实体为您使用的Form集合中的属性值。)

    ValidateAntiForgeryToken属性有助于防止跨站点请求伪造攻击。

    安全说明:Bind属性添加保护免受过度过帐例如,假设Student实体包括你不想要此 web 页后,可以更新的Secret财产。

       public class Student {
                   public int StudentID {
                           get; set; } public string LastName {
                                           get; set; } public string FirstMidName {
                                                           get; set; } public DateTime EnrollmentDate {
                                                                           get; set; } public string Secret {
                                                                                           get; set; } public virtual ICollection<Enrollment> Enrollments {
                                                                                                 get; set; } }

    即使你没有一个Secret字段在 web 页上,黑客可以使用一种工具如fiddler ,或者写一些 JavaScript,发布一个Secret窗体值。没有限制模型联编程序时它会创建一个Student实例,所使用的字段的绑定属性模型联编程序会拿起那Secret窗体值,用它来更新Student实体实例。然后无论价值黑客指定为Secret窗体字段将更新您的数据库中。下图显示了fiddler 工具 (与值"OverPost") 的Secret 字段中添加到已发布的窗体值。


    "OverPost"将然后将成功添加到 Secret属性插入行,虽然您从来没有打算 web 页将无法更新该属性的值。

    它是安全的最佳做法,Include参数用白名单中的字段的Bind属性。它也是可以到您想要排除的黑名单字段使用Exclude参数。Include是更安全的原因是当你向实体中添加新的属性,新的领域不会自动保护的Exclude列表。

    另一种替代方法,其中一个首选的许多人来说,是只查看模型使用模型绑定。视图模型包含只有您要绑定的属性。一旦完成了 MVC 模型联编程序,您将查看模型属性复制到的实体实例。

    除了在Bind属性try-catch块是搭建代码对您已经的更改。如果所做的更改在保存时,会捕获异常从DataException派生,显示一般错误消息。DataException异常有时是由外部的应用程序,而不是一个编程错误,某个东西导致的所以建议用户再试一次。虽然在此示例中未实施,生产高质量的应用会记录日志记录机制如ELMAH异常 (和非 null 内部异常).

    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.chstml还包括@Html.AntiForgeryToken(),其作品中的控制器有助于防止跨站点请求伪造攻击的ValidateAntiForgeryToken属性。

    不需要更改在Create.cshtml

  2. 运行该页面选择学生选项卡,然后单击Create.

    Student_Create_page

    一些数据验证的工作原理,默认情况。输入名称和无效的日期并单击 Create以查看错误消息。

    Students_Create_page_error_message

    以下突出显示的代码演示模型验证检查。

    [HttpPost]
    [ValidateAntiForgeryToken] public ActionResult Create(Student student) {
                              if (ModelState.IsValid) {
                                db.Students.Add(student); db.SaveChanges(); return RedirectToAction("Index"); } return View(student); }

    把日期改到一个有效的值,如 2005/9/1 并单击创建要看见出现在index页中的新学生。

    Students_Index_page_with_new_student

更新编辑文章页面

Controllers\StudentController.csHttpGetEdit方法 (没有HttpPost属性的一个) 使用Find方法检索所选的Student实体,正如您看到的Details方法。您不需要更改此方法。

但是,使用以下代码,以添加try-catch块和绑定属性替换HttpPost Edit操作方法:

[HttpPost]
[ValidateAntiForgeryToken] public ActionResult Edit( [Bind(Include = "StudentID, LastName, FirstMidName, EnrollmentDate")] Student student) {
                                  try {
                                      if (ModelState.IsValid) {
                                                db.Entry(student).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } } catch (DataException /* dex */) {
                                                                                       //Log the error (uncomment dex variable name after DataException 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); }

此代码是类似于您在HttpPost Create方法中看到。然而,而不是添加创建的模型联编程序到实体集的实体,此代码指示已更改的实体上设置一个标志。当调用SaveChanges方法时,修改国旗导致实体框架来创建 SQL 语句要更新的数据库行。将更新的数据库行的所有列,其中包括用户没有更改,并且忽略并发冲突。(您将了解如何处理并发稍后在本系列教程中)。

实体状态和附加 SaveChanges 方法

跟踪的数据库上下文是否在内存中的实体与它们相应的行在数据库中,同步此信息确定调用SaveChanges方法时,会发生什么。例如,当你传递给Add方法的一个新的实体,该实体的状态将设置为Added然后当你调用SaveChanges方法,数据库上下文发出 SQLINSERT命令。

实体可以处于以下状态之一:

  • Added该实体不存在尚未在数据库中。SaveChanges方法必须发出一个INSERT语句。
  • Unchanged什么都不需要去做与此实体SaveChanges法。当您从数据库中读取一个实体时,该实体开始与这种地位。
  • Modified某些或所有实体的属性值已被都修改。SaveChanges方法必须发出一个UPDATE语句。
  • Deleted该实体已标记为删除。SaveChanges方法必须发出DELETE语句。
  • Detached该实体不被跟踪的数据库上下文。

在桌面应用程序中,状态变化通常会自动设置。在桌面应用程序的类型中,您阅读的实体,并对一些其属性值进行更改。这将导致其实体的状态自动更改为Modified然后当你调用SaveChanges,实体框架生成更新仅有实际的属性更改 SQLUPDATE语句。

Web 应用程序的已断开连接的性质不允许为此连续的序列。读取实体的DbContext被处置后呈现的页面。当调用HttpPost Edit操作方法、 发送新的请求和你有DbContext的一个新实例时,所以你必须手动将实体状态设置为Modified.然后当您调用SaveChanges,实体框架更新的数据库行的所有列,因为该上下文有没有办法知道哪些属性更改。

如果您想要更新用户实际更改的字段的 SQLUpdate语句,可以以某种方式 (如隐藏字段) 保存的原始值,以便调用HttpPost Edit方法时,他们是可用。然后可以Student使用创建实体的原始值,调用Attach方法与该实体的原始版本,更新到新的值,该实体的值,然后调用SaveChanges.更多的信息,请参阅实体状态和 SaveChanges和 MSDN 数据开发人员中心中的本地数据

Views\Student\Edit.cshtml中的代码类似于你看到在Create.cshtml,并没有修改的必要。

通过选择学生选项卡,然后单击Edit超链接运行该页。

Student_Edit_page

改变的一些数据,单击保存你看到在索引页中更改的数据。

Students_Index_page_after_edit

更新删除页

Controllers\StudentController.csHttpGetDelete方法的模板代码使用Find方法检索所选的Student实体,正如您看到的DetailsEdit的方法。然而,若要实现自定义错误消息到SaveChanges调用失败时,您将向此方法和其相应的视图添加一些功能。

当你看到更新,并创建操作,删除操作需要两个操作方法。调用 GET 请求的响应的方法显示一个视图,使用户有机会批准或取消删除操作。如果用户批准它,则会创建一个 POST 请求。当发生这种情况时, HttpPost Delete方法称为,然后该方法实际上执行删除操作。

你会将try-catch块添加到HttpPost Delete方法,以处理对数据库进行更新时可能会出现的任何错误。如果发生错误,该HttpPost Delete方法调用HttpGet Delete方法,传递给它的参数,指示发生了错误。HttpGet Delete方法然后重新显示确认页和错误消息,使用户有机会取消或再试一次。

  1. 用下面的代码管理错误报告取代HttpGetDelete操作方法:
    public ActionResult Delete(bool? saveChangesError=false, int id = 0) {
                               if (saveChangesError.GetValueOrDefault()) {
                                         ViewBag.ErrorMessage = "Delete failed. Try again, and if the problem persists see your system administrator."; } Student student = db.Students.Find(id); if (student == null) {
                                                                           return HttpNotFound(); } return View(student); }

    这段代码接受一个可选的布尔参数指示是否它被称为后未能保存的更改。HttpGet Delete方法调用没有重复以前的错误时,此参数为false 。当它对数据库更新错误的响应HttpPost Delete方法调用时,参数为true和一条错误消息传递给视图。

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

    [HttpPost]
    [ValidateAntiForgeryToken] public ActionResult Delete(int id) {
                             try {
                                 Student student = db.Students.Find(id); db.Students.Remove(student); db.SaveChanges(); } catch (DataException/* dex */) {
                                                                    // uncomment dex and log error.  return RedirectToAction("Delete", new {
                                                                                 id = id, saveChangesError = true }); } return RedirectToAction("Index"); }

    此代码检索所选的实体,然后调用Remove方法,将该实体的状态设置为Deleted当调用SaveChanges时,生成 SQLDELETE的命令。Delete,也有从DeleteConfirmed 改变操作方法的名称。搭建的代码命名为DeleteConfirmed ,给出了HttpPost方法独特的签名HttpPost Delete方法。(CLR 需要有不同的方法参数的重载的方法)。现在,签名是独一无二的你可以坚持使用 MVC 公约并使用HttpPost相同的名称,HttpGet删除方法。

    如果在一个高容量应用程序提高性能是一个优先事项,你可以避免不必要的 SQL 查询,以检索行通过替换调用FindRemove的方法,用下面的代码,黄色突出显示框所示的代码行:

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

    此代码实例化一个Student实体使用唯一主键值,然后将实体状态设置为Deleted这是所有实体框架所需删除的实体。

    正如所指出,HttpGet Delete方法不会删除数据。执行删除操作响应 GET 请求 (或对于那件事,执行任何编辑操作,创建操作或更改数据的任何其他操作) 会产生安全风险。有关更多信息,请参见ASP.NET MVC 提示 #46 — — 不要使用删除链接,因为它们创建安全漏洞Stephen 瓦尔特的博客上。

  3. Views\Student\Delete.cshtml,添加一条错误消息之间的h2标题和h3标题中,如下面的示例所示:

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

    运行页上选择学生选项卡,然后单击删除超链接:

    Student_Delete_page

  4. 单击删除没有删除学生显示索引页。(您将看到的错误处理代码在处理并发教程稍后在这一系列行动中的示例。)

确保该数据库的连接是否关闭了

为了确保正确关闭数据库连接和他们持有腾出的资源,你应该看到它释放上下文实例。这就是为什么搭建的代码提供Dispose方法末尾的StudentController类中StudentController.cs,如下面的示例所示:

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

Controller基类已经实现IDisposable接口,所以这段代码只是添加重写Dispose(bool)方法来显式处理上下文实例。

摘要

你现在有一套完整的执行简单的 CRUD 操作,为Student实体的页面。MVC 佣工用于生成数据字段的 UI 元素。MVC 佣工有关的详细信息,请参见呈现的窗体使用 HTML 帮助器(页面是 MVC 3 但仍然相关的 MVC 4)。

在接下来的教程中会展开索引页的功能,通过添加排序和分页。

转载于:https://www.cnblogs.com/178mz/p/4259090.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_30810239/article/details/99843340

智能推荐

(附源码)spring boot火车订票系统 毕业设计 031012_火车购票系统三层数据流-程序员宅基地

文章浏览阅读1.3k次,点赞9次,收藏42次。车订票系统主要功能模块包括系统用户管理、车票中心、购票订票、退票纪录,采取面对对象的开发模式进行软件的开发和硬体的架设,能很好的满足实际使用的需求,完善了对应的软体架设以及程序编码的工作,采取MySQL作为后台数据的主要存储单元,采用Springboot框架、JSP技术、Ajax技术进行业务系统的编码及其开发,实现了本系统的全部功能。_火车购票系统三层数据流

mysql计算上个月,MySQL查询以计算上个月-程序员宅基地

文章浏览阅读95次。I would like to calculate total order amount in the previous month.I got the query for getting the data for the present month from the current date.SELECT SUM(goods_total) AS Total_Amount FROM orders..._mysql last month

JSP内置对象_pagecontext对象的作用范围有4个值-程序员宅基地

文章浏览阅读232次。内置对象的概述 在JSP页面中,有一些对象需要频繁使用,如果每次都重新创建这些对象则会非常麻烦。为了简化Web应用程序的开发,JSP2.0规范中提供了9个隐式(内置对象),他们是JSP默认创建的,可以直接在JSP页面中使用。这9个隐含对象的名称、类型和描述如表1-2所示。 名称 类型 ..._pagecontext对象的作用范围有4个值

3601劫持病毒分析报告_3601.exe-程序员宅基地

文章浏览阅读1.8k次。1.样本概况1.1 样本信息病毒名称:3601.exe所属家族:Trojan-DDoS.Win32.Macri.atkMD5值:b5752252b34a8af470db1830cc48504dMD5值:8a1716b566d20b77c20647d0f760b01cSHA1值:aec38add0aac1bc59bfaaf1e43dbdab10e13db181.2 测试环境及工具测试..._3601.exe

Python数据分析--服务器日志分析_python networkx 交换机日志分析-程序员宅基地

文章浏览阅读724次。作业:通过本周学习的内容, 使用pandas,matplotlib对服务器日志进行分析,检查有无异常情况发生.注意事项:1.文件命名规范.2.注释清晰.3.运行结果符合预期效果 .思路提示:1.pandas的基本数据处理和读取.2.matplotlib图像处理和显示.作业内容:1.导包,读取数据,设置数据的列名.2.对数据进行随机采样和信息异常值的检查注:对每列的进行异常值..._python networkx 交换机日志分析

手打51程序使用AS608指纹模块_51单片机指纹录入代码-程序员宅基地

文章浏览阅读531次,点赞11次,收藏10次。这些都是使用AS608中的重要内容,希望对想使用AS608模块的人有所帮助若想获取以上程序的代码,可添加我微信15113224982获取,不免费,一瓶可乐的价格。_51单片机指纹录入代码

随便推点

XSS 跨站点脚本漏洞详解_xss变形-程序员宅基地

文章浏览阅读307次。xss攻击手法以及绕过防御_xss变形

关于BISS Key的教程-程序员宅基地

文章浏览阅读3.5k次。网上我们一般查询到这样一些数据,如何识别? 例1:-----------------------------------------------------------------------------------------KBS World Telkom 1 at 108.0°E 3972 H 2100-3/4 DVB-S2/8PSK MPEG-4 SID(In Hex):_biss key

回炉夜话 - 序-程序员宅基地

文章浏览阅读159次。有志足风流,惜诺自可亲 这是我大学时代信奉的格言。转眼年至不惑,回想人生倒也是感慨万千。 在这里,作为一个老码农,我想梳理下自己的技术栈。为继续做一个码农而努力。 一、首先,对于各种技术的掌握程度作出如下定义: 了解: 阅读过相关资料或书籍,有可能..._回炉夜话全集

Android问题解决--“signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0xxxxxxx” 又出现了_to unreadable libraries. for unwinds of apps, only-程序员宅基地

文章浏览阅读1.2w次。今天,调试一个app,又出现“signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0xxxxxx”问题了。而且只在Android10以上版本才会有,导致的现象是app崩溃,这怎么怎?问题log:signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x739ae8d004全部log如下:05-08 10:21:31.065 D/a.module(1890.._to unreadable libraries. for unwinds of apps, only shared libraries

工件SSMwar exploded 部署工件时出错。请参阅服务器日志了解详细信息_正在构建工件 'ssm0950my8t:war exploded': 正在复制文件…-程序员宅基地

文章浏览阅读1.9k次。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。由于监听器过早的生效时间导致我们自动注入的bean的引用名称还没有生效(实际上bean已经注入了,但是监听器此时识别不到,小写类名首字母也没有用),这时候就要用到自定义bean名称了!仔细想一下,查看我监听器的代码,监听器实现了ServletContextListener接口,是一个全局监听器,也就是项目刚启动是就会生效,于是我添加了一条输出信息,就是“进入监听器”..._正在构建工件 'ssm0950my8t:war exploded': 正在复制文件…

字符串(python)_首先创建一个字符串str为“a little girl”,提取第3到13个字符,并组成新的字符串b-程序员宅基地

文章浏览阅读217次,点赞2次,收藏2次。(2)请统计字符串出现的每个字母的出现次数(忽略大小写,a 与 A 是同一个字母),并输出成一个字典。‘aAsmr3idd4bgs7Dlsf9eAF’,经过去除后,输出 ‘asmr3id4bg7lf9e’(4)按字符串中字符出现频率从高到低输出到列表,如果次数相同则按字母顺序排列。(3)请去除字符串多次出现的字母,仅留最先出现的一个,大小写不敏感。(1)请将字符串的数字取出,并输出成一个新的字符串。_首先创建一个字符串str为“a little girl”,提取第3到13个字符,并组成新的字符串b