1 9_Async and Stored Procedures with the Entity Framework in an ASP.NET MVC Application Mon Jul 06, 2015 8:12 am
Admin
Admin
In this tutorial you'll also see how to use stored procedures for insert, update, and delete operations on an entity.
Finally, you'll redeploy the application to Azure, along with all of the database changes that you've implemented since the first time you deployed.
The following illustrations show some of the pages that you'll work with.
Why bother with asynchronous code
A web server has a limited number of threads available, and in high load situations all of the available threads might be in use. When that happens, the server can’t process new requests until the threads are freed up. With synchronous code, many threads may be tied up while they aren’t actually doing any work because they’re waiting for I/O to complete. With asynchronous code, when a process is waiting for I/O to complete, its thread is freed up for the server to use for processing other requests. As a result, asynchronous code enables server resources to be use more efficiently, and the server is enabled to handle more traffic without delays.
In earlier versions of .NET, writing and testing asynchronous code was complex, error prone, and hard to debug. In .NET 4.5, writing, testing, and debugging asynchronous code is so much easier that you should generally write asynchronous code unless you have a reason not to. Asynchronous code does introduce a small amount of overhead, but for low traffic situations the performance hit is negligible, while for high traffic situations, the potential performance improvement is substantial.
For more information about asynchronous programming, see Use .NET 4.5’s async support to avoid blocking calls.
Create the Department controller
Create a Department controller the same way you did the earlier controllers, except this time select the Use async controller actions check box.
The following highlights show what was added to the synchronous code for the
- Code:
Index
public async Task
{
var departments = db.Departments.Include(d => d.Administrator);
return View(await departments.ToListAsync());
}
Four changes were applied to enable the Entity Framework database query to execute asynchronously:
- The method is marked with the
- Code:
async
- Code:
Task<ActionResult>
- The return type was changed from
- Code:
ActionResult
- Code:
Task<ActionResult>
- Code:
Task<T>
- Code:
T
- The
- Code:
await
- The asynchronous version of the
- Code:
ToList
Why is the
- Code:
departments.ToList
- Code:
departments = db.Departments
- Code:
departments = db.Departments
- Code:
ToList
- Code:
ToList
In the
- Code:
Details
- Code:
HttpGet
- Code:
Edit
- Code:
Delete
- Code:
Find
public async Task
{
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
- Code:
Create
- Code:
HttpPost Edit
- Code:
DeleteConfirmed
- Code:
SaveChanges
- Code:
db.Departments.Add(department)
public async Task
{
if (ModelState.IsValid)
{
db.Departments.Add(department);
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
Open Views\Department\Index.cshtml, and replace the template code with the following code:
@model IEnumerable
@{
ViewBag.Title = "Departments";
}
Departments
@Html.ActionLink("Create New", "Create")
@Html.DisplayNameFor(model => model.Name) | @Html.DisplayNameFor(model => model.Budget) | @Html.DisplayNameFor(model => model.StartDate) | Administrator | |
---|---|---|---|---|
@Html.DisplayFor(modelItem => item.Name) | @Html.DisplayFor(modelItem => item.Budget) | @Html.DisplayFor(modelItem => item.StartDate) | @Html.DisplayFor(modelItem => item.Administrator.FullName) | @Html.ActionLink("Edit", "Edit", new { id=item.DepartmentID }) | @Html.ActionLink("Details", "Details", new { id=item.DepartmentID }) | @Html.ActionLink("Delete", "Delete", new { id=item.DepartmentID }) |
This code changes the title from Index to Departments, moves the Administrator name to the right, and provides the full name of the administrator.
In the Create, Delete, Details, and Edit views, change the caption for the
- Code:
InstructorID
In the Create and Edit views use the following code:
In the Delete and Details views use the following code:
Administrator
Run the application, and click the Departments tab.
Everything works the same as in the other controllers, but in this controller all of the SQL queries are executing asynchronously.
Some things to be aware of when you are using asynchronous programming with the Entity Framework:
- The async code is not thread safe. In other words, in other words, don't try to do multiple operations in parallel using the same context instance.
- If you want to take advantage of the performance benefits of async code, make sure that any library packages that you're using (such as for paging), also use async if they call any Entity Framework methods that cause queries to be sent to the database.
Use stored procedures for inserting, updating, and deleting
Some developers and DBAs prefer to use stored procedures for database access. In earlier versions of Entity Framework you can retrieve data using a stored procedure by executing a raw SQL query, but you can't instruct EF to use stored procedures for update operations. In EF 6 it's easy to configure Code First to use stored procedures.
[list defaultattr=]
[*] In DAL\SchoolContext.cs, add the highlighted code to the
- Code:
OnModelCreating
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove
modelBuilder.Entity
.HasMany(c => c.Instructors).WithMany(i => i.Courses)
.Map(t => t.MapLeftKey("CourseID")
.MapRightKey("InstructorID")
.ToTable("CourseInstructor"));
modelBuilder.Entity
}
This code instructs Entity Framework to use stored procedures for insert, update, and delete operations on the
- Code:
Department
[*]In Package Manage Console, enter the following command:
- Code:
add-migration DepartmentSP
- Code:
Up
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 Package Manage Console, enter the following command:
- Code:
update-database
[*]Run the application in debug mode, click the Departments tab, and then click Create New.
[*]Enter data for a new department, and then click Create.
[*]In Visual Studio, look at the logs in the Output window to see that a stored procedure was used to insert the new Department row.
[/list]
Code First creates default stored procedure names. If you are using an existing database, you might need to customize the stored procedure names in order to use stored procedures already defined in the database. For information about how to do that, see Entity Framework Code First Insert/Update/Delete Stored Procedures .
If you want to customize what generated stored procedures do, you can edit the scaffolded code for the migrations
- Code:
Up
If you want to change an existing stored procedure that was created in a previous migration, you can use the Add-Migration command to generate a blank migration, and then manually write code that calls the AlterStoredProcedure method.
Deploy to Azure
This section requires you to have completed the optional Deploying the app to Azure section in the Migrations and Deployment tutorial of this series. If you had migrations errors that you resolved by deleting the database in your local project, skip this section.
[list defaultattr=]
[*] In Visual Studio, right-click the project in Solution Explorer and select Publish from the context menu.
[*]Click Publish.
Visual Studio deploys the application to Azure, and the application opens in your default browser, running in Azure.
[*]Test the application to verify it's working.
The first time you run a page that accesses the database, the Entity Framework runs all of the migrations
- Code:
Up
[/list]
Summary
In this tutorial you saw how to improve server efficiency by writing code that executes asynchronously, and how to use stored procedures for insert, update, and delete operations. In the next tutorial, you'll see how to prevent data loss when multiple users try to edit the same record at the same time.
Links to other Entity Framework resources can be found in the ASP.NET Data Access - Recommended Resources.