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

1.为什么使用异步代码

  一个服务器可用的线程数量是有限的,在高负载的情况下所有的可用线程都可能在使用。在这种情况下,在线程被释放之前服务器不能处理新的请求。在同步代码中,很多线程被占用但是实际上没有做任何操作,因为它们在等待I/O完成。在异步代码中,当一个进程在等待I/O完成的过程中,它的线程将会被释放用于处理其他请求。这样,异步代码可以更高效地使用服务器资源,并且使服务器可以没有延迟地处理更多访问。

  在之前的.NET版本中,编写和测试异步代码比较复杂、容易出错并且难以调试。在.NET 4.5中,编写、测试和调试异步代码变得非常简单,通常我们需要编写异步代码,除非我们有一个不这样做的理由。异步代码引入少量的开销,对于低流量情况下性能下降可以忽略不计,而对于高流量情况下性能改善的潜力巨大。

  更多关于异步编程信息请查看:Use .NET 4.5’s async support to avoid blocking calls

2.新建Department控制器

  查看产生的Index方法的代码:

  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>
  • await关键字被用于web service调用。当编译器遇到这个关键字,会在幕后将该方法分为两部分。第一部分以异步操作开始时结束。第二部分被放入操作完成后调用的回调方法中。
  • 异步版本的ToList扩展被调用。

  为什么 departments.ToList语句被修改而departments = db.Departments语句没有被修改呢?因为,只有执行查询或者被发送到数据库的命令才会异步执行。departments = db.Departments语句生成查询,但是查询在 departments.ToList语句才被执行。因此,只有ToList方法被异步执行。下面的代码中亦是同一原因:

  1. public async Task<ActionResult> Details(int? id)
  2. {
  3. if (id == null)
  4. {
  5. return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
  6. }
  7. Department department = await db.Departments.FindAsync(id);
  8. if (department == null)
  9. {
  10. return HttpNotFound();
  11. }
  12. return View(department);
  13. }
  1. public async Task<ActionResult> Create(Department department)
  2. {
  3. if (ModelState.IsValid)
  4. {
  5. db.Departments.Add(department);
  6. await db.SaveChangesAsync();
  7. return RedirectToAction("Index");
  8. }

  修改Views\Department\Index.cshtml

  1. @model IEnumerable<ContosoUniversity.Models.Department>
  2. @{
  3. ViewBag.Title = "Departments";
  4. }
  5. <h2>Departments</h2>
  6. <p>
  7. @Html.ActionLink("Create New", "Create")
  8. </p>
  9. <table class="table">
  10. <tr>
  11. <th>
  12. @Html.DisplayNameFor(model => model.Name)
  13. </th>
  14. <th>
  15. @Html.DisplayNameFor(model => model.Budget)
  16. </th>
  17. <th>
  18. @Html.DisplayNameFor(model => model.StartDate)
  19. </th>
  20. <th>
  21. Administrator
  22. </th>
  23. <th></th>
  24. </tr>
  25. @foreach (var item in Model) {
  26. <tr>
  27. <td>
  28. @Html.DisplayFor(modelItem => item.Name)
  29. </td>
  30. <td>
  31. @Html.DisplayFor(modelItem => item.Budget)
  32. </td>
  33. <td>
  34. @Html.DisplayFor(modelItem => item.StartDate)
  35. </td>
  36. <td>
  37. @Html.DisplayFor(modelItem => item.Administrator.FullName)
  38. </td>
  39. <td>
  40. @Html.ActionLink("Edit", "Edit", new { id=item.DepartmentID }) |
  41. @Html.ActionLink("Details", "Details", new { id=item.DepartmentID }) |
  42. @Html.ActionLink("Delete", "Delete", new { id=item.DepartmentID })
  43. </td>
  44. </tr>
  45. }
  46. </table>

  在Create、Delete、Details和Edit视图,将 InstructorID的标题改为“Administrator”:

    在Create和Edit视图:

  1. <label class="control-label col-md-2" for="InstructorID">Administrator</label>

    在Delete和Details视图:

  1. <dt>
  2. Administrator
  3. </dt>

  运行:

  在使用EF异步编程需要注意的问题:

  • 异步代码是线程不安全的。因此,不要试图使用同一个上下文实例并行处理多个操作。
  • 如果想要利用异步代码的性能优势,需要保证我们使用的库包(例如分页)在调用任何EF方法查询数据库时同样使用异步。

3.使用存储过程插入、更新和删除

  在早期的EF版本中,我们可以通过执行原生的SQL查询来使用存储过程查询数据,但是不能使用存储过程执行更新操作。在EF6中很容易配置Code First使用存储过程。

3.1.在DAL\SchoolContext.cs中添加代码:

  1. protected override void OnModelCreating(DbModelBuilder modelBuilder)
  2. {
  3. modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
  4. modelBuilder.Entity<Course>()
  5. .HasMany(c => c.Instructors).WithMany(i => i.Courses)
  6. .Map(t => t.MapLeftKey("CourseID")
  7. .MapRightKey("InstructorID")
  8. .ToTable("CourseInstructor"));
  9. modelBuilder.Entity<Department>().MapToStoredProcedures();
  10. }

  该行代码告诉EF在对Department进行插入、更新和删除操作时使用存储过程。

3.2.在Package Manage Console输入命令:

  1. add-migration DepartmentSP

  打开Migrations\<timestamp>_DepartmentSP.cs,可以看到:

  1. public override void Up()
  2. {
  3. CreateStoredProcedure(
  4. "dbo.Department_Insert",
  5. p => new
  6. {
  7. Name = p.String(maxLength: ),
  8. Budget = p.Decimal(precision: , scale: , storeType: "money"),
  9. 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: ),
  32. Budget = p.Decimal(precision: , scale: , 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. }

3.3.在Package Manage Console输入命令:

  1. update-database

3.4.运行:

  Code First创建默认的存储过程名。如果我们使用一个已经存在的数据库,为了使用数据库中已经定义的存储过程,我们需要指定存储过程的名字。更多信息请参考: Entity Framework Code First Insert/Update/Delete Stored Procedures

  如果我们想要指定产生的存储过程做什么,我们可以编辑迁移中的Up方法中产生存储过程的代码。通过这种方式,我们修改的代码不管是迁移运行时还是当部署后迁移自动在产品数据库运行都会起作用。

  如果我们想要修改一个在早期的迁移中创建的存储过程,我们可以使用Add-Migration命令来产生一个空白的迁移,然后手动编写调用AlterStoredProcedure方法的代码。

4.部署到Azure

  本节操作需要完成了之前可选的部署到Azure。如果我们遇到迁移错误,并且决定通过删除本地项目中的数据库来解决此问题,那么可以跳过本节。

4.1.在Visual Studio中选中项目右键,Solution Explorer选中Publish

4.2.点击Publish

4.3.测试程序是否正常工作。

[翻译][MVC 5 + EF 6] 9:异步和存储过程的更多相关文章

  1. [翻译][MVC 5 + EF 6] 12[完结]:高级场景

    原文:Advanced Entity Framework 6 Scenarios for an MVC 5 Web Application 1.执行原生SQL查询: EF Code First API ...

  2. [翻译][MVC 5 + EF 6] 11:实现继承

    原文:Implementing Inheritance with the Entity Framework 6 in an ASP.NET MVC 5 Application 1.选择继承映射到数据库 ...

  3. [翻译][MVC 5 + EF 6] 10:处理并发

    原文:Handling Concurrency with the Entity Framework 6 in an ASP.NET MVC 5 Application 1.并发冲突: 当一个用户编辑一 ...

  4. [翻译][MVC 5 + EF 6] 8:更新相关数据

    原文:Updating Related Data with the Entity Framework in an ASP.NET MVC Application 1.定制Course的Create和E ...

  5. [翻译][MVC 5 + EF 6] 7:加载相关数据

    原文:Reading Related Data with the Entity Framework in an ASP.NET MVC Application 1.延迟(Lazy)加载.预先(Eage ...

  6. [翻译][MVC 5 + EF 6] 6:创建更复杂的数据模型

    原文:Creating a More Complex Data Model for an ASP.NET MVC Application 前面的教程中,我们使用的是由三个实体组成的简单的数据模型.在本 ...

  7. [翻译][MVC 5 + EF 6] 5:Code First数据库迁移与程序部署

    原文:Code First Migrations and Deployment with the Entity Framework in an ASP.NET MVC Application 1.启用 ...

  8. [翻译][MVC 5 + EF 6] 4:弹性连接和命令拦截

    原文:Connection Resiliency and Command Interception with the Entity Framework in an ASP.NET MVC Applic ...

  9. [翻译][MVC 5 + EF 6] 3:排序、过滤、分页

    原文:Sorting, Filtering, and Paging with the Entity Framework in an ASP.NET MVC Application 1.添加排序: 1. ...

随机推荐

  1. zabbix 3.0 安装

    zabbix3.0安装注意: 1.PHP要5.4版本以上 2.防火墙关闭 3.selinux关闭 注:本操作系统为centos 6.5 X86   操作步骤 一.安装PHP 添加 epel 源 # r ...

  2. iOS 键盘框架IQKeyboardManager使用

    框架地址:https://github.com/hackiftekhar/IQKeyboardManager AppDelegate.m文件中   #import <IQKeyboardMana ...

  3. 使用JDK自带jvisualvm监控tomcat

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...

  4. orderby group by

    说到SQL语句,大家最開始想到的就是他的查询语句: select* from tableName: 这是最简单的一种查询方式,不带有不论什么的条件. 当然在我们的实际应用中,这条语句也是非经常常使用到 ...

  5. 理解CRC校验

    举个最简单的例子,A向B发送一个数字,B如何检测数字在传输过程中有没有发生错误呢? A和B之间,定下一个协议,两边都知道一个除数X,A向B发送数字的时候,同时把余数附带后面发过去.比如,两边定的除数是 ...

  6. cocos 3.0 一键打包android平台应该注意的细节

    cocos2d-x 移植越来越便捷,走到cocos2d-x-3.0rc2,能够说移植已经非常完好了,我们仅仅要进行适当的适配,cocos能够直接帮助我们生成apk 我网络不好无法上传图片:(无图无捷豹 ...

  7. [Bootstrap] 4. Typogrphy

    What is Typography When we talk about typography, it's a big subject! Which of the following fall un ...

  8. android学习日记03--常用控件checkbox/radiobutton

    常用控件3.checkbox 复选框,确定是否勾选,点击一下勾选,点击第二下取消,当有一系列备选项时适合用checkbox控件,方便用户提交数据. 贴上例子Activity的java代码 packag ...

  9. careercup-C和C++ 13.4

    13.4 深拷贝和浅拷贝有什么区别,如何使用? 解答 浅拷贝并不复制数据,只复制指向数据的指针,因此是多个指针指向同一份数据. 深拷贝会复制原始数据,每个指针指向一份独立的数据.通过下面的代码, 可以 ...

  10. 封装,capsulation,&&继承,Inheritance,&&多态,polymorphism

    Inheritance&&polymorphism 层次概念是计算机的重要概念.通过继承(inheritance)的机制可对类(class)分层,提供类型/子类型的关系.C++通过类派 ...