MVC5+EF6--9 异步及存储过程

近期学习MVC5+EF6,找到了Microsoft的原文,一个非常棒的系列,Getting Started with Entity Framework 6 Code First using MVC 5,网址:http://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application。

这个系列的原文,可以上面网址找到。我也从网上找到了相关的译文。申明,这些译文,我不是原创,而是从网上找来的,为避免下次还要网上查询,现将这些译文整理放在上面。以后找时间将原文地址附上。

原文网址:

  • 这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第七篇:为ASP.NET MVC应用程序更新相关数据

原文:Async and Stored Procedures with the Entity Framework in an ASP.NET MVC Application

译文版权所有,谢绝全文转载——但您可以在您的网站上添加到该教程的链接。

在之前的教程中,您已经学习了如何使用同步编程模型来读取和更新数据。在本教程中您将看到如何实现异步编程模型。因为能够更好地使用服务器资源,异步代码可以帮助应用程序更好地执行。

在本教程中您还会看到如何使用存储过程对实体进行插入、更新和删除操作。

下面的插图显示了您将要编写的页面:

为什么要使用麻烦的异步代码

一个WEB服务器只有很有限的可用线程,并且在高负载的情况下,可能所有的线程都会在使用中。当发生这种情况时,服务器将无法处理新的请求,直到有线程被释放。在同步代码的情况下,多个线程可能会关联起来,但实际上它们并不作任何工作而只是在等待IO完成。使用异步代码,当一个进程正在等待IO完成时,它的线程可以服务器腾出从而用于处理其他请求。因此,异步代码可以更高效地使用服务器资源,并且服务器能够在不延迟的情况下处理更多的流量。

在较早版本的.NET中,编写和测试异步代码是一件复杂、容易出错且难以调试的工作。在.Net 4.5中,编写、测试和调试异步代码变得简单起来,你应当总是使用异步代码,除非有理由不允许你这样做。异步代码会花费很少量的开销,但对于低流量情况下性能的损失是微不足道的。对于高流量的情况下,潜在的性能提示是巨大的。

有关异步编程的更多信息,请参阅 Use .NET 4.5’s async support to avoid blocking calls。

创建系控制器

使用之前你创建其他控制器相同的方式来创建一个系控制器,但这次我们选择使用异步控制器操作选项。

下面的代码中,高亮部分显示了异步方法和同步方法的不同之处:

view sourceprint?

1.public async Task<ActionResult> Index()

2.{

3.var departments = db.Departments.Include(d => d.Administrator);

4.return View(await departments.ToListAsync());

5.}

我们应用了四个更改来启用实体框架数据库执行异步查询:

该方法使用了async关键字,它告诉编译器生成回调方法体的部分,并自动创建Task<ActionResult>返回对象。 返回类型从ActionResult更改为Task<ActionResult>。Task<T>类型表示正在进行的任务具有类型为T的结果。 await关键字被应用到web服务调用。当编译器看到有此关键字时,在后台将该方法分为两个部分。第一部分结束于异步操作启动,第二部分被放入一个操作完成时的回调方法。 调用了ToList扩展方法的异步版本。

为什么只修改departments.ToList语句而不是departments= db.Departments语句?原因是只有被发送的数据库执行的查询或语句才能够使用异步执行。departments=db.Departments语句设置了一个查询,但直到调用ToList方法时该查询都不会执行。因此,只有ToList方法是异步执行的。

在Details方法和Httpget的Edit和Delete方法中,Find方法是导致查询被发送到数据库进行检索的方法,所以该方法是可以异步执行的。

view sourceprint?

01.public async Task<ActionResult> Details(int? id)

02.{

03.if (id == null)

04.{

05.return new HttpStatusCodeResult(HttpStatusCode.BadRequest);

06.}

07.Department department = await db.Departments.FindAsync(id);

08.if (department == null)

09.{

10.return HttpNotFound();

11.}

12.return View(department);

13.}

在Create,HttpPost的Edit和DeleteConfirmed方法中,是SaveChanges方法导致命令执行,而像db.Department.Add(department)方法只是导致实体在内存中的修改。

view sourceprint?

01.public async Task<ActionResult> Create([Bind(Include="DepartmentID,Name,Budget,StartDate,InstructorID")] Department department)

02.{

03.if (ModelState.IsValid)

04.{

05.db.Departments.Add(department);

06.await db.SaveChangesAsync();

07.return RedirectToAction("Index");

08.}

09.

10.ViewBag.InstructorID = new SelectList(db.Instructors, "ID", "LastName", department.InstructorID);

11.return View(department);

12.}

打开Views\Department\Index.cshtml,并使用下面的代码替换原来的:

view sourceprint?

01.@model IEnumerable<ContosoUniversity.Models.Department>

02.

03.@{

04.ViewBag.Title = "Departments";

05.}

06.

07.<h4>Departments</h4>

08.

09.<p>

10.@Html.ActionLink("Create New", "Create")

11.</p>

12.<table class="table">

13.<tr>

14.<th>

15.@Html.DisplayNameFor(model => model.Name)

16.</th>

17.<th>

18.@Html.DisplayNameFor(model => model.Budget)

19.</th>

20.<th>

21.@Html.DisplayNameFor(model => model.StartDate)

22.</th>

23.<th>Administrator</th>

24.<th></th>

25.</tr>

26.

27.@foreach (var item in Model)

28.{

29.<tr>

30.<td>

31.@Html.DisplayFor(modelItem => item.Name)

32.</td>

33.<td>

34.@Html.DisplayFor(modelItem => item.Budget)

35.</td>

36.<td>

37.@Html.DisplayFor(modelItem => item.StartDate)

38.</td>

39.<td>

40.@Html.DisplayFor(modelItem => item.Administrator.FullName)

41.</td>

42.<td>

43.@Html.ActionLink("Edit", "Edit", new { id = item.DepartmentID }) |

44.@Html.ActionLink("Details", "Details", new { id = item.DepartmentID }) |

45.@Html.ActionLink("Delete", "Delete", new { id = item.DepartmentID })

46.</td>

47.</tr>

48.}

49.

50.</table>

代码修改了标题,并将系主任列移动到右边,同时提供了系主任的姓名。

在创建、删除、详情和编辑视图中,将InstructorID字段的标题更改为"系主任",类似之前你在课程视图中将系名称字段更改为"系"中那样。

在创建和编辑视图使用下面的代码:

view sourceprint?

1.@Html.DisplayFor(model => model.Department.Name)

在删除和详细视图使用下面的代码:

view sourceprint?

1.<dt>

2.Administrator

3.</dt>

运行该应用程序,并点击系选项卡。

程序正常地运行,就跟其他的控制器一样。但在此控制器中,所有SQL查询都是异步执行的。

当您在实体框架中使用异步编程要注意的一些事情:

异步代码不是线程安全的。换言之,不要使用同一个上下文实例以并行方式来执行多个操作。 如果你想要利用异步代码的性能优势,请确保您正在使用的所有库软件包(例如分页),在包中进行的数据库查询等任何实体框架方法也使用异步执行。

用于插入、更新和删除的存储过程

一些开发人员和DBA更愿意使用存储过程来访问数据库。早期版本的实体框架中,您可以使用执行原始SQL查询的方式来检索数据来执行存储过程,但您不能使用存储过程来用于更新操作。在实体框架6中,您可以很容易地配置Code First来使用存储过程。

在DAL\SchoolContext.cs中,将高亮的代码添加到OnModelCreating方法。

view sourceprint?

01.protected override void OnModelCreating(DbModelBuilder modelBuilder)

02.{

03.modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

04.

05.modelBuilder.Entity<Course>()

06..HasMany(c => c.Instructors).WithMany(i => i.Courses)

07..Map(t => t.MapLeftKey("CourseID")

08..MapRightKey("InstructorID")

09..ToTable("CourseInstructor"));

10.modelBuilder.Entity<Department>().MapToStoredProcedures();

11.}

此代码指示实体框架使用存储过程来进行Department实体的插入、更新和删除操作。

在程序包管理控制台中,输入以下命令:

view sourceprint?

1.add-migration DepartmentSP

打开Migrations\<时间戳>_DepartmentSP.cs,参阅Up方法中的代码,你会看到插入、更新和删除的存储过程:

view sourceprint?

01.public override void Up()

02.{

03.CreateStoredProcedure(

04."dbo.Department_Insert",

05.p => new

06.{

07.Name = p.String(maxLength: 50),

08.Budget = p.Decimal(precision: 19, scale: 4, storeType: "money"),

09.StartDate = p.DateTime(),

10.InstructorID = p.Int(),

11.},

12.body:

13.@"INSERT [dbo].[Department]([Name], [Budget], [StartDate], [InstructorID])

14.VALUES (@Name, @Budget, @StartDate, @InstructorID)

15.

16.DECLARE @DepartmentID int

17.SELECT @DepartmentID = [DepartmentID]

18.FROM [dbo].[Department]

19.WHERE @@ROWCOUNT > 0 AND [DepartmentID] = scope_identity()

20.

21.SELECT t0.[DepartmentID]

22.FROM [dbo].[Department] AS t0

23.WHERE @@ROWCOUNT > 0 AND t0.[DepartmentID] = @DepartmentID"

24.);

25.

26.CreateStoredProcedure(

27."dbo.Department_Update",

28.p => new

29.{

30.DepartmentID = p.Int(),

31.Name = p.String(maxLength: 50),

32.Budget = p.Decimal(precision: 19, scale: 4, storeType: "money"),

33.StartDate = p.DateTime(),

34.InstructorID = p.Int(),

35.},

36.body:

37.@"UPDATE [dbo].[Department]

38.SET [Name] = @Name, [Budget] = @Budget, [StartDate] = @StartDate, [InstructorID] = @InstructorID

39.WHERE ([DepartmentID] = @DepartmentID)"

40.);

41.

42.CreateStoredProcedure(

43."dbo.Department_Delete",

44.p => new

45.{

46.DepartmentID = p.Int(),

47.},

48.body:

49.@"DELETE [dbo].[Department]

50.WHERE ([DepartmentID] = @DepartmentID)"

51.);

52.

53.}

在软件包管理器控制台中,输入以下命令:

view sourceprint?

1.update-database

在调试模型下运行该应用程序,单击系选项卡,然后单击创建。 为一个新系输入相关数据然后单击创建。
 在VS中的输出窗口查看日志。

Code First使用默认名创建了存储过程。如果您正在使用现有的数据库,您可能需要自定义存储过程的名称,有关如何操作的信息,请参阅Entity Framework Code First Insert/Update/Delete Stored Procedures 。

如果你想要自定义存储过程,你可以编辑迁移中的脚手架代码里的Up方法来创建存储过程。使用这种方法时您的更改将在应用迁移时或部署到生产环境后自动进行。

如果你想修改一个在之前的迁移中已经创建的的存储过程,你可以使用Add-Migration命令来生成一个空白的迁移,然后手动编写代码调用AlterStoredProcedure方法。

部署到Windows Azure

本章跳过……

总结

在本教程中,您看到了如何提高服务器效率。通过编写异步执行代码以及使用存储过程来进行插入、更新和删除操作。在接下来的教程中,您将看到当多个用户试图编辑同一条纪录时如何防止数据丢失。

作者信息

Tom Dykstra - Tom Dykstra是微软Web平台及工具团队的高级程序员,作家。

延伸阅读:

时间: 2024-11-08 20:21:31

MVC5+EF6--9 异步及存储过程的相关文章

MVC5+EF6 入门完整教程九

前一阵子临时有事,这篇文章发布间隔比较长,我们先回顾下之前的内容,每篇文章用一句话总结重点. 文章一 MVC核心概念简介,一个基本MVC项目结构 文章二 通过开发一个最基本的登录界面,介绍了如何从Controller中获取表单数据 文章三 EF的整个开发过程 文章四 EF基本的CRUD和常用的HtmlHelper 文章五 使用布局页(模板页)改造UI 文章六 分部视图(Partial View) 文章七 排序过滤分页 文章八 不丢失数据进行数据库结构升级 以上如果有不清楚的可以再回去看一下. 文

MVC5+EF6 入门完整教程十

本篇是第一阶段的完结篇. 学完这篇后,你应该可以利用MVC进行完整项目的开发了. 本篇主要讲述多表关联数据的更新,以及如何使用原生SQL. 文章提纲 多表关联数据更新 如何使用原生SQL 总结 多表关联数据更新 我们在第四篇文章已经讲过数据的更新了,不过那个是针对单表结构的更新. 这次我们讲下使用EF进行关联数据的更新. 关联数据更新有两种情况: 1.一对多 2.多对多 第一种情况关联表有主外键关联,只要简单的更新外键值就可以了(相当于更新单表),我们主要讲解第二种多对多的情况. 使用之前很熟悉

[实战]MVC5+EF6+MySql企业网盘实战(5)——ajax方式注册

写在前面 今天贴合到实际的客户需求仔细的想了下,其实在userInfo这个类里面很多字段都不是必须的.有很多的事业单位根本就不能上网,填写的邮箱也是exchange的,个人的详细信息都在ad里面可以取到,再这里重新注册一次确实没有必要.所以对注册的字段重新筛选了一下.对于目前大多数网站来说,要么就是采用第三方的登录方式,要么就是非常简单的注册方式,对我本人来说,如果非必要,我喜欢第三方的登录方式.当然,简单的注册信息,可以更方便用户,也可以在用户注册后,为用户提供积分系统等让用户完善个人资料来增

MVC5+EF6 完整教程17--升级到EFCore2.0(转)

MVC5+EF6 完整教程17--升级到EFCore2.0 2017年08月22日 14:48:12 linux12a 阅读数:2814 EF Core 2.0上周已经发布了,我们也升级到core 文章内容基于vs2017,请大家先安装好vs2017(15.3). 本篇文章主要讲下差异点,跟之前一样的就不再重复了. 文章目录(差异点): 一.新建项目, EF配置/使用 过程的变化 二.身份验证方式的变化(达到类似于原form认证效果) 三.使用原生SQL方式变化 四.读取config过程(默认取

构建ASP.NET MVC5+EF6+EasyUI 1.5+Unity4.x注入的后台管理系统(1)-前言与目录(持续更新中...)

前言: 起初写这个框架的时候,可以说在当时来说并不是很流行的设计模式,那是在2012年,面向对象的编程大家都很熟悉, 但是“注入.控制反转(DI,IOC,依赖注入).AOP切面编程”新兴名词 很多人并不知道特别是从事.NET开发的人,至少在当时 是这么样的,但是在今天它们却是非常流行的技术指标,很多大牛也承认,这是主流的开发模式,你们可以从招聘网的技术岗位看出. 我从事过MVC2.0到5.0的相关开发工作,见证了MVC的成熟演变过程,就像本框架一样,设计模式未曾改变,但是代码一直在重 构.我也坚

[实战]MVC5+EF6+MySql企业网盘实战(23)——文档列表

写在前面 上篇文章实现了图片列表,这篇文章实现文档列表将轻车熟路,因为逻辑基本相似,只是查询条件的不同.这里将txt,doc,docx,ppt,pptx,xls,xlsx的文件都归为文档列表中. 系列文章 [EF]vs15+ef6+mysql code first方式 [实战]MVC5+EF6+MySql企业网盘实战(1) [实战]MVC5+EF6+MySql企业网盘实战(2)——用户注册 [实战]MVC5+EF6+MySql企业网盘实战(3)——验证码 [实战]MVC5+EF6+MySql企业

构建ASP.NET MVC5+EF6+EasyUI 1.4.3+Unity4.x注入的后台管理系统(51)-系统升级

系统很久没有更新内容了,最近花了2个月的时间每天一点点,从原有系统 MVC4+EF5+UNITY2.X+Quartz 2.0+easyui 1.3.4无缝接入 MVC5+EF6+Unity4.x+Quartz 2.3 +easyui 1.4.3. 并以easyui 1.4.3的gray皮肤为基础,升级10个扁平化皮肤 皮肤查看地址 更新的主要目的:新的MVC5特性和更好的性能 记录一下升级过程. 1.除了web层,其他全部提取. 2.新建解决方案.以前命名空间为App.现在更名为Apps. 3.

[实战]MVC5+EF6+MySql企业网盘实战(13)——思考

写在前面 从上面更新编辑文件夹,就一直在思考一个问题,之前做的编辑文件名已经文件夹名称,只是逻辑上的修改,但是保存的物理文件或者文件夹名称并没有进行修改,这样就导致一个问题,就是在文件或者文件夹修改名称后就会找不到物理文件,因为路径或者文件名错误了.所以就有了这篇文章的思考.当然,修改物理文件确实能实现,但是会频繁的操作io,性能会非常的差,如果一个文件非常大,你可想而知这种效率有多么底下. 系列文章 [EF]vs15+ef6+mysql code first方式 [实战]MVC5+EF6+My

[实战]MVC5+EF6+MySql企业网盘实战(9)——编辑文件名

写在前面 上篇文章实现了文件的下载,本篇文章将实现编辑文件名的功能. 系列文章 [EF]vs15+ef6+mysql code first方式 [实战]MVC5+EF6+MySql企业网盘实战(1) [实战]MVC5+EF6+MySql企业网盘实战(2)——用户注册 [实战]MVC5+EF6+MySql企业网盘实战(3)——验证码 [实战]MVC5+EF6+MySql企业网盘实战(4)——上传头像 [Bootstrap]modal弹出框 [实战]MVC5+EF6+MySql企业网盘实战(5)——