[翻译][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。然后当我们调用SaveChanges时,EF将会产生只更新被改变了字段的SQL。

  但是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会保证这些修改同时执行成功或失败。

时间: 2024-07-30 06:08:37

[翻译][MVC 5 + EF 6] 2:基础的增删改查(CRUD)的相关文章

MVC + EF 框架 对数据库做增删改查

这几天一直在看MVC 开发模式,其中借助EF框架对数据库进行 增删改查操作 现在就小小的总结一下吧 在使用EF操作数据库时,会首先添加 ADO.NET数据模型,这时,会为我们添加一个数据上下文类,使用这个类的对象可以对数据库做任何操作.所以在使用EF操作数据库之前 需要创建数据上下文对象. MyDatabaseEntities mde = new MyDatabaseEntities(); 1.使用EF 对数据库 做增加操作 1.1 创建一个需要被操作数据表的对象(一般来说 ,一张表就是一个实体

MVC3+EF4.1学习系列(二)-------基础的增删改查和持久对象的生命周期变化

上篇文章中 我们已经创建了EF4.1基于code first的例子  有了数据库 并初始化了一些数据  今天这里写基础的增删改查和持久对象的生命周期变化 学习下原文先把运行好的原图贴来上~~ 一.创建详细页 首先 我们先在控制器下 添加详细页的方法 因为这篇文章后面要介绍持久对象声明周期的变化 所以在这里先看下有哪些状态 EF里一共有这五中生命状态类型 其实 看名字我们可以大概猜测出个一二三来~~  游离的 未改变的  新添加的  已删除的 修改的  但是是怎么变化的能 我们在后面的代码中实践与

基础的增删改查,数据库优化,索引

mysql的特点 关系型数据库,免费使用, 插入式存储引擎, 性能高, 基础的增删改查 ddl语句,数据定义语句 123456789101112 create database test1;drop database test1;use test1;create table emp(ename varchar(10),hiredate date,sal decimal(10,2),deptno int(2));drop table emp;alter table emp modify ename

week_one-python基础 列表 增删改查

# Author:larlly'''#列表增删改查#定义列表name = ["wo","ni","ta","wo"] #定义列表num_list = list(range(1,10)) #range生成范围的数,强制转化为列表#查print(num_list)print(name[0])print(name[0:2]) #顾头不顾尾print(name[-1])print(name[:]) #取所有值print(name[-3

小白5分钟上手c#数据库操作(二) 基础的增删改查

上一小节,我们已经准备好了一个数据库文件,现在我们先不用微软包装好的各种Entity Framework, 自己用基础的方法对数据库进行增删改查. 前期准备: 新建一个console工程,把上一小节的数据库拷贝到工程目录下,copy local 设置成true, 目录结构大致长这样: 然后添加一个nuget包,方面后面使用各种c#提供的方法: 基本上常用的操作里,查数据是一类,增删改是一类 先看怎么查数据: // 查询数据 using (var connection = new SQLiteCo

ADO.NET基础(增删改查)

ADO.NET是一种数据访问技术,就是将C#和MSSQL连接起来的一个纽带.可以通过ADO.NET将内存中的临时数据写入到数据库中,也可以将数据库中的数据提取到内存中供程序调用. ADO.NET是所有数据访问技术的基础. 一.连接数据库基本格式 两个类:1.数据库连接类 SqlConnection2.数据库操作类 SqlCommand 二.连接数据库基本步骤 (一)增.改.删 1.连接数据库写连接字符串,立马就要想到有4点要写完,1.连接哪台服务器,2.连接哪个数据库,3.连接用户名,4.密码s

MySQL 基础知识 增删改查基本操作

增删改查=CRUD 增 insertINSERT car VALUES('字符','name','brand','1990-02-02 00:00:00') 添加一条 INSERT car (`code`,`name`)VALUES('1','2') 单独添加 删除 DELETE 不常用DELETE FROM car 删除表的所有信息DELETE FROM car WHERE `Code`='字符' AND `Name`='name'DELETE FROM car WHERE `Code`='字

SqL语句基础之增删改查

增查删改的SQL语句,如此的实用,下面我就来简单介绍一下它简单的用法. 1.什么是SQL? SQL是用于访问和处理数据库的标准的一种计算机语言. 2.SQL可以做什么?  (1)可以向数据库进行查询  (2)可以向数据库插入数据  (3) 可以更新数据库中的数据  (4)可以删除数据库中的数据  (5)可以向数据库新增数据 ps:总的可以大体的分为增,删,改,查 3.怎么编写SQL语言? 现在主要编写SQL语言的工具是SQL server,由微软公司发布出来的,由于数据库更新比较繁琐,所以当前使

PHP学习之[第08讲]数据库MySQL基础之增删改查

一.工具: 1.phpMyAdmin (http://www.phpmyadmin.net/) 2.Navicat (http://www.navicat.com/) 3.MySQL GUI Tools (http://dev.mysql.com/downloads/gui-tools/) 二.语法: 数据类型 描述 应用范围 int,smallint 整型,常用int型,取值最大11位 点击量,编号,真假 char ,varchar 字符串型,char最大取值255字节,varchar更长并伸