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

智能推荐

python编码问题之encode、decode、codecs模块_python中encode在什么模块-程序员宅基地

文章浏览阅读2.1k次。原文链接先说说编解码问题编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。 Eg:str1.decode('gb2312') #将gb2312编码的字符串转换成unicode编码str2.encode('gb2312') #将unicode编码..._python中encode在什么模块

Java数据流-程序员宅基地

文章浏览阅读949次,点赞21次,收藏15次。本文介绍了Java中的数据输入流(DataInputStream)和数据输出流(DataOutputStream)的使用方法。

ie浏览器无法兼容的问题汇总_ie 浏览器 newdate-程序员宅基地

文章浏览阅读111次。ie无法兼容_ie 浏览器 newdate

想用K8s,还得先会Docker吗?其实完全没必要-程序员宅基地

文章浏览阅读239次。这篇文章把 Docker 和 K8s 的关系给大家做了一个解答,希望还在迟疑自己现有的知识储备能不能直接学 K8s 的,赶紧行动起来,K8s 是典型的入门有点难,后面越用越香。

ADI中文手册获取方法_adi 如何查看数据手册-程序员宅基地

文章浏览阅读561次。ADI中文手册获取方法_adi 如何查看数据手册

React 分页-程序员宅基地

文章浏览阅读1k次,点赞4次,收藏3次。React 获取接口数据实现分页效果以拼多多接口为例实现思路加载前 加载动画加载后 判断有内容的时候 无内容的时候用到的知识点1、动画效果(用在加载前,加载之后就隐藏或关闭,用开关效果即可)2、axios请求3、map渲染页面4、分页插件(antd)代码实现import React, { Component } from 'react';//引入axiosimport axios from 'axios';//引入antd插件import { Pagination }_react 分页

随便推点

关于使用CryPtopp库进行RSA签名与验签的一些说明_cryptopp 签名-程序员宅基地

文章浏览阅读449次,点赞9次,收藏7次。这个变量与验签过程中的SignatureVerificationFilter::PUT_MESSAGE这个宏是对应的,SignatureVerificationFilter::PUT_MESSAGE,如果在签名过程中putMessage设置为true,则在验签过程中需要添加SignatureVerificationFilter::PUT_MESSAGE。项目中使用到了CryPtopp库进行RSA签名与验签,但是在使用过程中反复提示无效的数字签名。否则就会出现文章开头出现的数字签名无效。_cryptopp 签名

新闻稿的写作格式_新闻稿时间应该放在什么位置-程序员宅基地

文章浏览阅读848次。新闻稿是新闻从业者经常使用的一种文体,它的格式与内容都有着一定的规范。本文将从新闻稿的格式和范文两个方面进行介绍,以帮助读者更好地了解新闻稿的写作_新闻稿时间应该放在什么位置

Java中的转换器设计模式_java转换器模式-程序员宅基地

文章浏览阅读1.7k次。Java中的转换器设计模式 在这篇文章中,我们将讨论 Java / J2EE项目中最常用的 Converter Design Pattern。由于Java8 功能不仅提供了相应类型之间的通用双向转换方式,而且还提供了转换相同类型对象集合的常用方法,从而将样板代码减少到绝对最小值。我们使用Java8 功能编写了..._java转换器模式

应用k8s入门-程序员宅基地

文章浏览阅读150次。1,kubectl run创建pods[root@master ~]# kubectl run nginx-deploy --image=nginx:1.14-alpine --port=80 --replicas=1[root@master ~]# kubectl get podsNAME READY STATUS REST...

PAT菜鸡进化史_乙级_1003_1003 pat乙级 最优-程序员宅基地

文章浏览阅读128次。PAT菜鸡进化史_乙级_1003“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。得到“答案正确”的条件是: 1. 字符串中必须仅有 P、 A、 T这三种字符,不可以包含其它字符; 2. 任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x 或者是空字符串,或..._1003 pat乙级 最优

CH340与Android串口通信_340串口小板 安卓给安卓发指令-程序员宅基地

文章浏览阅读5.6k次。CH340与Android串口通信为何要将CH340的ATD+Eclipse上的安卓工程移植到AndroidStudio移植的具体步骤CH340串口通信驱动函数通信过程中重难点还存在的问题为何要将CH340的ATD+Eclipse上的安卓工程移植到AndroidStudio为了在这个工程基础上进行改动,验证串口的数据和配置串口的参数,我首先在Eclipse上配置了安卓开发环境,注意在配置环境是..._340串口小板 安卓给安卓发指令