天天看點

MVC5 Entity Framework學習之異步和存儲過程為什麼要使用異步代碼建立Department控制器在insert, update和delete操作中使用存儲過程部署到Windows Azure

在之前的文章中,你已經學習了如何使用同步程式設計模型來讀取和更新資料,在本節中你将學習如何實作異步程式設計模型。異步可以使應用程式執行更有效率,因為它可以更有效的使用伺服器資源。

同樣在本節中你還将學習如何針對實體的insert, update, 和delete操作使用存儲過程。

最後将應用程式部署到 Windows Azure。

下面是完成後的頁面

MVC5 Entity Framework學習之異步和存儲過程為什麼要使用異步代碼建立Department控制器在insert, update和delete操作中使用存儲過程部署到Windows Azure
MVC5 Entity Framework學習之異步和存儲過程為什麼要使用異步代碼建立Department控制器在insert, update和delete操作中使用存儲過程部署到Windows Azure

為什麼要使用異步代碼

一個web伺服器的可用線程是有限的,在高負載情況下,所有的可用線程可能都在被使用。當出現這種情況時,伺服器将無法處理新的請求,直到有線程被釋放。使用同步代碼,大量線程将被鎖定,但實際上它們并未作任何工作而隻是在等待IO完成。使用異步代碼,當一個程序正在等待IO完成時,它的線程會被伺服器釋放并去處理其它的請求。是以,異步代碼可以更高效地使用伺服器資源,并且能夠在沒有延遲的情況下處理更多的流量。

在.NET的早期版本中,編寫和測試異步代碼是複雜的、易于出錯的,且難以調試。但在.Net 4.5中,編寫、測試和調試異步代碼是如此簡單,是以你應該經常使用異步代碼。異步代碼會花費較少的開銷,在低流量情況下,對性能的影響是可以忽略不計的,但在高流量的情況下,潛在性能的提升是巨大的。

建立Department控制器

建立一個Department控制器,選中Use async controller actions 複選框

MVC5 Entity Framework學習之異步和存儲過程為什麼要使用異步代碼建立Department控制器在insert, update和delete操作中使用存儲過程部署到Windows Azure

檢視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 頁籤

MVC5 Entity Framework學習之異步和存儲過程為什麼要使用異步代碼建立Department控制器在insert, update和delete操作中使用存儲過程部署到Windows Azure

程式運作一切正常,但在此控制器中,所有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

MVC5 Entity Framework學習之異步和存儲過程為什麼要使用異步代碼建立Department控制器在insert, update和delete操作中使用存儲過程部署到Windows Azure

6.在 Visual Studio的Output視窗可以看到使用了存儲過程來插入了Department行

MVC5 Entity Framework學習之異步和存儲過程為什麼要使用異步代碼建立Department控制器在insert, update和delete操作中使用存儲過程部署到Windows Azure

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

我的小站:MVC5 Entity Framework學習(9):異步和存儲過程

還大家一個健康的網絡環境,從你我做起

THE END

繼續閱讀