Translation: Introduction to Entity Framework 6 using MVC5 (9)-using asynchronous and stored procedures for ASP.NET MVC applications

Use asynchronous and stored procedures for ASP.NET MVC applications

This is a translation of Microsoft's official tutorial Getting Started with Entity Framework 6 Code First using MVC 5 series, here is the ninth article: Using asynchronous and stored procedures for ASP.NET MVC applications

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


In the previous tutorial, you have learned how to use the synchronous programming model to read and update data. In this tutorial you will see how to implement an asynchronous programming model. Because of the better use of server resources, asynchronous code can help applications execute better.

In this tutorial you will also see how to use stored procedures to insert, update, and delete entities.

The following illustration shows the page you will write:

departments

createdepartment

Why use troublesome asynchronous code

A WEB server has only a limited number of available threads, and under high load, all threads may be in use. When this happens, the server will not be able to process new requests until a thread is released. In the case of synchronous code, multiple threads may be associated, but in fact they do not do any work but just wait for IO to complete. Using asynchronous code, when a process is waiting for IO to complete, its threads can be freed by the server to process other requests. Therefore, asynchronous code can use server resources more efficiently, and the server can handle more traffic without delay.

In earlier versions of .NET, writing and testing asynchronous code was complex, error-prone, and difficult to debug. In .Net 4.5, writing, testing, and debugging asynchronous code becomes simple. You should always use asynchronous code unless you are not allowed to do so for a reason. Asynchronous code will cost very little overhead, but the performance loss is negligible for low-traffic situations. For high-traffic situations, the potential performance hints are huge.

For more information about asynchronous programming, see Use .NET 4.5's async support to avoid blocking calls .

Create a system controller

Create a system controller in the same way that you created other controllers before, but this time we chose to use the asynchronous controller operation option.

departmentscaffold

In the following code, the highlighted part shows the difference between the asynchronous method and the synchronous method:

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

We applied four changes to enable the Entity Framework database to perform asynchronous queries:

  • This method uses the async keyword, which tells the compiler to generate part of the callback method body and automatically create a Task<ActionResult>return object.
  • The return type was changed from ActionResult Task<ActionResult>. Task<T>Type indicates that the ongoing task has a result of type T.
  • The await keyword is applied to web service calls. When the compiler sees this keyword, it divides the method into two parts in the background. The first part ends when the asynchronous operation starts, and the second part is put into a callback method when the operation is completed.
  • The asynchronous version of the ToList extension method is called.

Why only modify the departments.ToList statement instead of the departments = db.Departments statement? The reason is that only queries or statements executed by the database being sent can be executed asynchronously. The departments = db.Departments statement sets up a query, but the query will not be executed until the ToList method is called. Therefore, only the ToList method is executed asynchronously.

In the Details method and Httpget's Edit and Delete methods, the Find method is the method that causes the query to be sent to the database for retrieval, so this method can be executed asynchronously.

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

In the Edit and DeleteConfirmed methods of Create, HttpPost, it is the SaveChanges method that causes the command to execute, while methods like db.Department.Add (department) just cause the modification of the entity in memory.

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

Open Views \ Department \ Index.cshtml and replace the original with the following code:

@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>

The code modifies the title and moves the department head column to the right, while providing the name of the department head.

In the Create, Delete, Detail, and Edit views, change the title of the InstructorID field to "Department Head", similar to how you changed the Department Name field to "Department" in the Course View.

Use the following code in creating and editing views:

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

Use the following code in the delete and detailed views:

<dt>
    Administrator
</dt>

Run the application and click on the Department tab.

departments

The program runs normally, just like other controllers. But in this controller, all SQL queries are executed asynchronously.

Some things to note when you use asynchronous programming in Entity Framework:

  • Asynchronous code is not thread safe. In other words, do not use the same context instance to perform multiple operations in parallel.
  • If you want to take advantage of the performance advantages of asynchronous code, please make sure that all the library packages you are using (such as paging), any Entity Framework methods such as database queries in the package also use asynchronous execution.

Stored procedures for insert, update and delete

Some developers and DBAs prefer to use stored procedures to access the database. In earlier versions of the Entity Framework, you can use the original SQL query to retrieve data to execute stored procedures, but you cannot use stored procedures for update operations. In Entity Framework 6, you can easily configure Code First to use stored procedures.

  • In DAL \ SchoolContext.cs, add the highlighted code to the OnModelCreating method.
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();
}

This code instructs the Entity Framework to use stored procedures to insert, update, and delete Department entities.

  • In the package management console, enter the following command:
add-migration DepartmentSP

Open Migrations \ <timestamp> _DepartmentSP.cs, refer to the code in the Up method, you will see the stored procedures for insert, update and 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)"
    );

}
  • In the package manager console, enter the following command:
update-database
  • Run the application under the debug model, click the Department tab, and then click Create.
  • Enter the relevant data for a new department and click Create.

createdepartment

  • View the log in the output window in VS.

departmentinsertsp

Code First created the stored procedure using the default name. If you are using an existing database, you may need to customize the name of the stored procedure. For information on how to do this, see Entity Framework Code First Insert / Update / Delete Stored Procedures .

If you want to customize the stored procedure, you can edit the Up method in the scaffolding code in the migration to create the stored procedure. With this method, your changes will be made automatically when the application is migrated or after deployment to the production environment.

If you want to modify a stored procedure that has been created in the previous migration, you can use the Add-Migration command to generate a blank migration, and then manually write code to call the AlterStoredProcedure method.

Deploy to Windows Azure

slightly…

to sum up

In this tutorial, you saw how to improve server efficiency. Insert, update, and delete operations by writing asynchronous execution code and using stored procedures. In the next tutorial, you will see how to prevent data loss when multiple users try to edit the same record.

author information

tom-dykstra Tom Dykstra -Tom Dykstra is a senior programmer and writer on the Microsoft Web Platform and Tools team.

Published 40 original articles · 25 praises · 100,000+ views

Guess you like

Origin blog.csdn.net/yym373872996/article/details/53129276