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

智能推荐

域名--泛解析-程序员宅基地

文章浏览阅读78次。背景:主域名下多数子域名访问后直接跳转至www域名的服务。百度百科--域名泛解析:在域名前添加任何子域名,均可访问到所指向的WEB地址。也就是客户的域名#.com之下所设的*.#.com全部。泛域名解析:利用通配符* (星号)来做次级域名以实现所有的次级域名均指向同一IP地址。子域名挖掘: 泛解析这个问题的解决方法很简单,向DNS请求*记录,然后把枚举子域名回来的..._dns枚举泛解析

基于对赋值为随机数的数组实现打印、求和及最大值、平均值的计算,排序问题_编写一个方法,对数组的元素用[0,100)之间的随机数进行初始化,初始化之后对数组进-程序员宅基地

文章浏览阅读206次。我们先定义一个数组x并为其分配储存空间,如下:int[] x=new x[100] 想要对数组中的每一个元素进行随机数赋值,需要用到循环控制语句,这里以for循环为例:定义一个变量i并赋值为0,作为for循环的起始条件;需要注意的是,数组的下标是从0开始的,比如x[0]到x[99],代表数组的长度为100。所以再写入判断语句的时候,不能写成a<=x.length;控制变量语句应写入自加语句。在循环体里,对x[a]进行随机数赋值,以0到100为例如图: 完成对x[a]的赋值之后,开始写入打印代_编写一个方法,对数组的元素用[0,100)之间的随机数进行初始化,初始化之后对数组进

为什么eMule总是未连接到服务器-程序员宅基地

文章浏览阅读1k次。<一>安装和版本问题1) eMule对Windows有什么要求?eMule能在Windows 95版本以上的Windows操作系统下运行。1个好的P2P软件需要好的拨号网络的支持,所以Windows 98和Windows ME的比较差网络运行情况可能会影响eMule的发挥;相对来说Windows 2000和Windows XP更适合使用eMule。2) 弹出错误信息说oleacc.dl..._emule v0.50b 最新服务器未连接

14 种编程语言书写关机脚本,真香_如何写强制关机脚本-程序员宅基地

文章浏览阅读2w次,点赞19次,收藏49次。批处理版本C 语言版本C++ 语言版本JAVA 语言版本C# 语言版本Python 语言版本NodeJS 语言版本PHP 语言版本Perl 语言版本Go 语言版本VB 语言版本SQL 语言版本树莓派 版本易语言 版本期待评论区故事的起源,有个家伙发来一个 BAT 的关机脚本,我顺手给改成了 八种语言的。_如何写强制关机脚本

docker compose搭建elasticsearch7集群_insufficient buffer remaining for aead cipher frag-程序员宅基地

文章浏览阅读4.1k次,点赞2次,收藏7次。一、集群介绍系统环境:Centos7.5服务器节点:主机名 IP hadoop03 192.168.1.153 hadoop04 192.168.1.154 hadoop05 192.168.1.155 二、环境准备1、安装docker:略过2、安装docker compose1)使用官方推荐方式(此方式需服务器翻外网)curl -L "https://github.com/docker/compose/releases/download_insufficient buffer remaining for aead cipher fragment (2). needs to be more

Debian10安装部署DNS服务-正向解析篇_debian10安装powerdns-程序员宅基地

文章浏览阅读6k次,点赞7次,收藏39次。1、服务安装1.1、服务安装执行下面的命令安装apt install -y bind9 dnsutils1.2、配置文件作用服务安装完成之后,执行下面的命令查看配置文件列表ls -l /etc/bind然后得到下面的信息root@debian:~# ls -l /etc/bind总用量 48-rw-r--r-- 1 root root 2761 5月 18 16:02 bind.keys-rw-r--r-- 1 root root 237 5月 18 16:02 db.0_debian10安装powerdns

随便推点

保研福利|九月CS保研冲刺大礼包!-程序员宅基地

文章浏览阅读20次。将原资料精简打包只为你能轻装上阵,冲刺梦校!▼志愿填报手册【九推版本】▼填报有疑问?九推无offer?这里有超详细的志愿填报指南,助你填报无忧!超周到的防鸽策略&捡漏策略,助你成功上岸!叮咚!九月份岛主发送的福利已经“上门”啦~亲,注意查收哦~

探秘MIP-NeRF:谷歌的实时三维重建新利器-程序员宅基地

文章浏览阅读371次,点赞5次,收藏5次。探秘MIP-NeRF:谷歌的实时三维重建新利器项目地址:https://gitcode.com/google/mipnerf项目简介MIP-NeRF 是由谷歌研究团队推出的一项创新性项目,它基于神经辐射场(NeRF)技术,旨在实现更高效、更真实的3D场景重建和渲染。该项目的目标是将复杂的三维建模过程简化为一个快速、实时的过程,让用户体验到前所未有的视觉效果。技术解析NeRF(神经辐射场...

poj1703 犯罪团伙 并查集_poj 团伙 倍增并查集-程序员宅基地

文章浏览阅读710次,点赞2次,收藏2次。 在讲解这个题目之前, 我不得不狠狠的吐槽cin和cout的效率, 我提交了6遍都是超时, 最后一遍提交时统统把cin和cout改为scanf和printf才过的, 当时心情又高兴又难受. 查看题目点击这里 Find them, Catch them POJ - 1703吐槽完了, 开始讲题. 第一次遇见这种题目是感觉满头痛的, 咦~, 并查集不是将关系是朋..._poj 团伙 倍增并查集

LeetCode-14-最长公共前缀(C)_leetcode最长公共前缀 c-程序员宅基地

文章浏览阅读113次。文章首发及后续更新:http://mwhls.top/617.html新的更新内容请到mwhls.top查看。如果没有图片请到上方的文章首发页面查看。昨天刷题做二阶字符串指针的时候又出问题了,所以今天换了个简单难度的题。结果结果!我又出问题了!可恶!不过解决了:C语言二级字符串指针的使用(函数传参/长度获取/空间分配) 题目编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""。示例 1:输入: ["f_leetcode最长公共前缀 c

java/php/node.js/python基于Java的医疗器械销售系统【2024年毕设】-程序员宅基地

文章浏览阅读32次。除了以上作品下面是2023-2024年最新100套计算机专业原创的毕业设计源码+数据库,是近期作品,如果你的题目刚好在下面可以文末领取java源码参考。后台主要是管理员,管理员功能包括首页、个人中心、用户管理、器械分类管理、器械商品管理、留言反馈、系统管理、订单管理等;springboot基于springboot的电子书阅读系统的开发与设计。springboot基于springboot的健康生活管理系统。springboot基于Android的小说阅读与创作的平台。

MySQL 之多表连查_mysql连表查询-程序员宅基地

文章浏览阅读5.8k次。连接是关系数据库模型的主要特点,连接查询是关系数据库中最主要的查询,主要包括内连接、外连接等.通过连接运算符可以实现多个表查询,在关系数据库管理系统中,表建立时各数据之间的关系不必确定,常把一个实体的所有信息存放在一个表中.当查询数据时,通过连接操作查询出存放在多个表中的不同实体的信息.当两个或多个表中存在相同意义的字段时,便可以通过这些字段对不同的表进行连接查询._mysql连表查询