MVC5 Entity Framework学习之异步和存储过程

在之前的文章中,你已经学习了如何使用同步编程模型来读取和更新数据,在本节中你将学习如何实现异步编程模型。异步可以使应用程序执行更有效率,因为它可以更有效的使用服务器资源。

同样在本节中你还将学习如何针对实体的insert, update, 和delete操作使用存储过程。

最后将应用程序部署到 Windows Azure。

下面是完成后的页面

为什么要使用异步代码

一个web服务器的可用线程是有限的,在高负载情况下,所有的可用线程可能都在被使用。当出现这种情况时,服务器将无法处理新的请求,直到有线程被释放。使用同步代码,大量线程将被锁定,但实际上它们并未作任何工作而只是在等待IO完成。使用异步代码,当一个进程正在等待IO完成时,它的线程会被服务器释放并去处理其它的请求。因此,异步代码可以更高效地使用服务器资源,并且能够在没有延迟的情况下处理更多的流量。

在.NET的早期版本中,编写和测试异步代码是复杂的、易于出错的,且难以调试。但在.Net 4.5中,编写、测试和调试异步代码是如此简单,所以你应该经常使用异步代码。异步代码会花费较少的开销,在低流量情况下,对性能的影响是可以忽略不计的,但在高流量的情况下,潜在性能的提升是巨大的。

创建Department控制器

创建一个Department控制器,选中Use async controller actions 复选框

查看Index方法中添加的异步代码

public async Task<ActionResult> Index()
{
    var departments = db.Departments.Include(d => d.Administrator);
    return View(await departments.ToListAsync());
}

共有四处更改来让Entity Framework使用异步执行数据库查询:

  • 方法使用了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方法会将查询发送到数据库去执行,所以该方法是异步执行的。

public async Task<ActionResult> Details(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Department department = await db.Departments.FindAsync(id);
    if (department == null)
    {
        return HttpNotFound();
    }
    return View(department);
}

在Create,HttpPost Edit和DeleteConfirmed方法中,调用SaveChanges方法时会引起命令的执行,而像db.Department.Add(department)方法仅仅是在内存中修改实体。

public async Task<ActionResult> Create(Department department)
{
    if (ModelState.IsValid)
    {
        db.Departments.Add(department);
    await db.SaveChangesAsync();
        return RedirectToAction("Index");
    }

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

@model IEnumerable<ContosoUniversity.Models.Department>
@{
    ViewBag.Title = "Departments";
}
<h2>Departments</h2>
<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Name)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Budget)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.StartDate)
        </th>
    <th>
            Administrator
        </th>
        <th></th>
    </tr>
@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Name)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Budget)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.StartDate)
        </td>
    <td>
            @Html.DisplayFor(modelItem => item.Administrator.FullName)
            </td>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id=item.DepartmentID }) |
            @Html.ActionLink("Details", "Details", new { id=item.DepartmentID }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.DepartmentID })
        </td>
    </tr>
}
</table>

上面的代码将标题从Index 更改为Departments,将Administrator 名称移动到右侧,并提供了Administrator 的全名。

在Create, Delete,,Details和Edit视图中,将InstructorID字段的标题修改为Administrator

在Create 和Edit视图中使用下面的代码

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

在Delete和Details视图中使用下面的代码

<dt>
    Administrator
</dt>

运行项目,点击Departments 选项卡

程序运行一切正常,但在此控制器中,所有SQL查询都是异步执行的。

当你使用Entity Framework来进行异步编程时要注意:

  • 异步代码不是线程安全的。换句话说,不要使用同一个上下文实例并行执行多个操作。
  • 如果你希望能够利用异步代码的性能优势,请确保你正在使用的所有库包(例如分页)在调用任何Entity Framework方法并将查询发送至数据库时也同样要使用异步执行。

在insert, update和delete操作中使用存储过程

某些开发人员和DBA喜欢使用存储过程来进行数据库访问。在Entity Framework的早期版本中,你可以通过原始SQL查询来使用存储过程来检索数据,但是你不能在更新操作中使用存储过程。在Entity Framework 6中,你可以通过配置Code First来使用存储过程。

1.打开DAL\SchoolContext.cs,在OnModelCreating 方法中添加如下代码

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    modelBuilder.Entity<Course>()
        .HasMany(c => c.Instructors).WithMany(i => i.Courses)
        .Map(t => t.MapLeftKey("CourseID")
            .MapRightKey("InstructorID")
            .ToTable("CourseInstructor"));
    modelBuilder.Entity<Department>().MapToStoredProcedures();
}

上面的代码指定Entity Framework对于Department 实体的insert,update和delete操作使用存储过程。

2.在Package Manage Console中输入如下命令

add-migration DepartmentSP

打开Migrations\<timestamp>_DepartmentSP.cs,查看Up方法中创建的Insert, Update和Delete存储过程

public override void Up()
{
            CreateStoredProcedure(
        "dbo.Department_Insert",
        p => new
            {
                Name = p.String(maxLength: 50),
                Budget = p.Decimal(precision: 19, scale: 4, storeType: "money"),
                StartDate = p.DateTime(),
                InstructorID = p.Int(),
            },
        body:
            @"INSERT [dbo].[Department]([Name], [Budget], [StartDate], [InstructorID])
              VALUES (@Name, @Budget, @StartDate, @InstructorID)

              DECLARE @DepartmentID int
              SELECT @DepartmentID = [DepartmentID]
              FROM [dbo].[Department]
              WHERE @@ROWCOUNT > 0 AND [DepartmentID] = scope_identity()

              SELECT t0.[DepartmentID]
              FROM [dbo].[Department] AS t0
              WHERE @@ROWCOUNT > 0 AND t0.[DepartmentID] = @DepartmentID"
    );

            CreateStoredProcedure(
        "dbo.Department_Update",
        p => new
            {
                DepartmentID = p.Int(),
                Name = p.String(maxLength: 50),
                Budget = p.Decimal(precision: 19, scale: 4, storeType: "money"),
                StartDate = p.DateTime(),
                InstructorID = p.Int(),
            },
        body:
            @"UPDATE [dbo].[Department]
              SET [Name] = @Name, [Budget] = @Budget, [StartDate] = @StartDate, [InstructorID] = @InstructorID
              WHERE ([DepartmentID] = @DepartmentID)"
    );

            CreateStoredProcedure(
        "dbo.Department_Delete",
        p => new
            {
                DepartmentID = p.Int(),
            },
        body:
            @"DELETE [dbo].[Department]
              WHERE ([DepartmentID] = @DepartmentID)"
    );

}

3.在Package Manage Console中输入如下命令

update-database

4.运行项目,点击Departments选项卡,然后点击Create New

5.输入数据,点击Create

6.在 Visual Studio的Output窗口可以看到使用了存储过程来插入了Department行

Code First使用默认名称创建了存储过程。如果你正在使用现有的数据库,你可能需要自定义存储过程的名称以便使用数据库中已定义的存储过程。

如果你希望自定义存储过程,你可以编辑Up方法中创建存储过程的框架代码。当不论何时进行迁移时,你所做的这些更改会被表现出来,当在部署后迁移自动在生产环境中运行时,你所做的这些更改就会被应用到生产环境数据库。

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

部署到Windows Azure

本节需要你完成之前的MVC5 Entity Framework学习之Code First迁移和部署教程中的将应用程序部署到Windows Azure章节,如果在迁移中出现错误,你需要删除本地数据库来解决它。

1.在Visual Studio的Solution Explorer中,右键单击项目,选择Publish

2.点击Publish,Visual Studio会将应用程序部署到Windows Azure并在浏览器中打开该程序

3.测试应用程序以验证其是否工作正常

当你第一次运行应用程序并访问数据库时,Entity Framework会执行所有迁移中的Up方法来确保数据模型的一致性。

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

欢迎转载,请注明文章出处:http://blog.csdn.net/johnsonblog/article/details/39272637

还大家一个健康的网络环境,从你我做起

THE END

时间: 2024-12-21 17:25:12

MVC5 Entity Framework学习之异步和存储过程的相关文章

MVC5 Entity Framework学习

MVC5 Entity Framework学习(1):创建Entity Framework数据模型 MVC5 Entity Framework学习(2):实现基本的CRUD功能 MVC5 Entity Framework学习(3):添加排序.筛选和分页功能 MVC5 Entity Framework学习(4):弹性连接和命令拦截 MVC5 Entity Framework学习(5):Code First迁移和部署 MVC5 Entity Framework学习(6):创建复杂的数据模型 MVC5

MVC5 Entity Framework学习之实现主要的CRUD功能

在上一篇文章中,我们使用Entity Framework 和SQL Server LocalDB创建了一个MVC应用程序,并使用它来存储和显示数据.在这篇文章中,你将对由 MVC框架自己主动创建的CRUD(create, read, update, delete)代码进行改动. 注意:通常我们在控制器和数据訪问层之间创建一个抽象层来实现仓储模式.为了将注意力聚焦在怎样使用实体框架上.这里暂没有使用仓储模式. 在本篇文章中,要创建的web页面: watermark/2/text/aHR0cDovL

MVC5 Entity Framework学习之更新相关数据

在上篇文章中学习了如何在页面中显示相关数据,本节中将学习如何对相关数据进行更新.对于大多数实体关系,可以通过更新外键或导航属性来更新数据,对于多对多关系,Entity Framework不会直接公开连接表,所以你需要通过相应的导航属性来添加和移除实体. 先看完成后的效果图 为Courses自定义Create 和Edit 页面 当一个新的course实体被创建时,该实体必须关联到一个已存在的department.要做到这一点,生成的框架代码应该要包括控制器方法和用于选择department的下列列

MVC5 Entity Framework学习之弹性连接和命令拦截

到目前为止,应用程序一直在本地IIS Express上运行.如果你想让别人通过互联网访问你的应用程序,你必须将它部署到WEB服务器同时将数据库部署到数据库服务器 本篇文章中将教你如何使用在将你的应用程序部署到云环境时的Entity Framework 6的非常有价值的两个特性:弹性连接(瞬时错误的自动重试)和命令拦截(捕获所有发送到数据库的SQL查询语句并记录至日志中). 1.启用弹性连接 当你将应用程序部署到Windows Azure时,相应的数据库部也应被部署到Windows Azure S

MVC5 Entity Framework学习之Entity Framework高级功能

在之前的文章中,你已经学习了如何实现每个层次结构一个表继承.本节中你将学习使用Entity Framework Code First来开发ASP.NET web应用程序时可以利用的高级功能. 在本节中你将重用之前已经创建的页面,接下来你需要新建一个页面并使用原始SQL来批量更新数据库中所有Course的学分. 在Department Edit页面中添加新的验证逻辑并使用非跟踪查询. 执行原始SQL查询 Entity FrameworkCode First API包含有可以让你直接向数据库发送SQ

MVC5 Entity Framework学习之读取相关数据

前一篇文章中完成了School 数据模型,接下来你将学习如何读取和显示相关的数据--这里指Entity Framework加载至导航属性中的数据. 下图是完成后的效果图 延迟.预先和显示加载相关数据 Entity Framework可以通过多种方法向实体的导航属性中加载数据 延迟加载(Lazy loading) 当实体第一次被读取时,相关数据并不会被检索.但是,当你第一次访问导航属性时,该导航属性所需的数据会自动加载.这是向数据库发送多个查询语句的结果--一次是读取实体本身,接着是每次与被检索的

MVC5 Entity Framework学习之处理并发

之前你已经学习了如何更新数据,那么在本节你将学习如何在当多个用户在同一时间更新同一实体时处理冲突. 修改与Department实体相关的那些页面以便它们能够i处理并发错误.下面的截图是Index 和Delete页面,以及当出现并发冲突时的错误消息. 并发冲突 当一个用户对实体的数据进行编辑,然后另一个用户在前一个用户将更改写入到数据库之前更新同一实体的数据时将发生并发冲突.如果你没有启用冲突检测,那么最后一次对数据库的更新将会覆盖其他用户对数据库所做的更改.在大部分应用程序中,这种风险是可以接受

MVC5 Entity Framework学习之Entity Framework高级功能(转)

在之前的文章中,你已经学习了如何实现每个层次结构一个表继承.本节中你将学习使用Entity Framework Code First来开发ASP.NET web应用程序时可以利用的高级功能. 在本节中你将重用之前已经创建的页面,接下来你需要新建一个页面并使用原始SQL来批量更新数据库中所有Course的学分. 在Department Edit页面中添加新的验证逻辑并使用非跟踪查询. 执行原始SQL查询 Entity FrameworkCode First API包含有可以让你直接向数据库发送SQ

MVC5 Entity Framework学习之实现继承

之前你已经学习了如何处理并发异常,在本节中你将学习如何实现继承. 在面向对象的编程中,你可以使用继承来重用代码.接下来你将修改Instructor和Student类,让它们派生自Person基类,该基类包含instructor和student共有的属性如LastName.你不需要添加或修改任何WEB页面,但是你需要修改某些代码,这些修改会自动反映在数据库中. 映射继承到数据库的选项 School 数据模型中的Instructor和Student类有几个相同的属性: 假设你希望通过共享Instru