EF学习笔记(九):异步处理和存储过程

总目录:ASP.NET MVC5 及 EF6 学习笔记 - (目录整理)html

上一篇:EF学习笔记(八):更新关联数据web

本篇原文:Async and Stored Procedures数据库

为什么要采用异步?windows

一个Web服务器确定有可用线程的限制,那么在一些访问量特别大的状况下,线程确定会消耗完;这个时候服务器确定处理不了请求,必须等线程里处理结束才能够处理请求;安全

在非异步的时候,不少线程都处于等待状态,并非一直在工做,而是在等相似于I/O等处理结束;服务器

采用异步的时候,当一个处理在等待I/O处理结束的时候,能够先去作作其余事情;多线程

因此异步处理可使服务器更为高效,较低延迟的状况下处理更多的请求。mvc

在早期的.NET中,写或者测试异步处理都是很复杂的,庆幸的是.NET 4.5之后写或者测试异步处理请求代码都很是简单,除非有特别的理由不采用异步处理;app

异步处理确实会有一些多出来的系统开销,对于低流量的应用,效果能够忽略,但对于大流量的应用,效果是很明显的;异步

更专业的资料: Use .NET 4.5's async support to avoid blocking calls.

下面作些代码测试:

采用异步方式新建Department控制器:

 

自动生成的Index Action:

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

与非异步方式,有4处不一样来实现EF异步请求数据:

一、请求方法加上了async标志关键字,等于告诉编译器这个方法中有部分方法体为异步的,须要生成针对部分方法体的异步回调,而且自动建立一个Task<ActionResult>对象做为异步返回;

二、返回类型从ActionResult变为Task<ActionResult>,Task<T>代表后续处理将使用T类型;

三、await关键字引用于Call Web Service,当编译器看到await这个关键字,就会把这个方法分为两部分,第1部分就是开始异步处理,第2部分就是异步处理完成后,再回调的部分;

四、采用ToList的异步版本方法;

(原文后面一段没看明白。。。感受有些笔误以及思路没理清楚)

接后面改几个视图,把Index视图里稍微改下,显示Administrator的全名:

@model IEnumerable<EFTest.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>

把Create\Edit视图中 InstructorID 字段标题 改成 Administrator ,把原来一行注释掉,增长一行:

     <div class="form-group">
            <label class="control-label col-md-2" for="InstructorID">Administrator</label>
            @*@Html.LabelFor(model => model.InstructorID, "InstructorID", htmlAttributes: new { @class = "control-label col-md-2" })*@
            <div class="col-md-10">
                @Html.DropDownList("InstructorID", null, htmlAttributes: new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.InstructorID, "", new { @class = "text-danger" })
            </div>
        </div>
@model EFTest.Models.Department

@{
    ViewBag.Title = "Delete";
}

<h2>Delete</h2>

<h3>Are you sure you want to delete this?</h3>
<div>
    <h4>Department</h4>
    <hr />
    <dl class="dl-horizontal">
        @*<dt>
            @Html.DisplayNameFor(model => model.Administrator.LastName)
        </dt>

        <dd>
            @Html.DisplayFor(model => model.Administrator.LastName)
        </dd>*@
        <dt>
            Administrator
        </dt>
        <dd>
            @Html.DisplayFor(model => model.Administrator.FullName)
        </dd>
        <dt>
            @Html.DisplayNameFor(model => model.Name)
        </dt>

        <dd>
            @Html.DisplayFor(model => model.Name)
        </dd>

        <dt>
            @Html.DisplayNameFor(model => model.Budget)
        </dt>

        <dd>
            @Html.DisplayFor(model => model.Budget)
        </dd>

        <dt>
            @Html.DisplayNameFor(model => model.StartDate)
        </dt>

        <dd>
            @Html.DisplayFor(model => model.StartDate)
        </dd>

    </dl>

    @using (Html.BeginForm()) {
        @Html.AntiForgeryToken()

        <div class="form-actions no-color">
            <input type="submit" value="Delete" class="btn btn-default" /> |
            @Html.ActionLink("Back to List", "Index")
        </div>
    }
</div>

Delete\Detail如上面修改方法;

效果:

看起来的效果和其余控制器同样。。。但这个控制器后台查询处理数据都是异步方式。

对于异步方式,有两点须要注意:

一、异步方式没法线程安全,换句话说,不要尝试同一个上下文实例来并行屡次处理;

二、若是你要享受到异步方式的好处,记得全部使用到的而且涉及到数据库操做的类库(例如:分页)都须要采用异步方式;

 

采用存储过程来进行增删改

一些DBA比较推荐使用存储过程来进行数据操做,之前版本的EF只能经过存储过程取数据,更新数据作不到,而如今EF6就很简单能够实现;

把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();
}

这样EF就会采用存储过程进行Department的操做;

首先先要数据库升级一下,创建好存储过程;在PMC中输入 add-migration DepartmentSP

而后在数据库迁移目录里就能够看到最新的日期时间戳的XXXXXXXXXXXXX_DepartmentSP.sc文件,打开这个文件就能够看到里面向数据库里增长了3个存储过程;

在PMC中输入update-database,执行完的结果,能够到数据库里查看:

有3个存储过程被产生;

其余代码都不用改动,在执行Department增删改的时候,EF会自动调用这个存储过程来进行。

如今采用的方式是EF Code First直接定义存储过程名的方式,若是要使用本身数据库中已有的存储过程,则参考:Entity Framework Code First Insert/Update/Delete Stored Procedures.

若是想本身定制存储过程的产生,能够在迁移中定义的up方法中来修改。

若是要改变一个已有的之前版本创建的存储过程,可使用Add-Migration建立一个空的迁移,而后在一个叫AlterStoredProcedure方法中手动写代码;

相关文章
相关标签/搜索