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方法中手動寫代碼;

相關文章
相關標籤/搜索