Introduction to EntityFramework 6 Part 4: asynchronous operations and logging

Introduction

In the previous post we looked at CRUD operations in EntityFramework 6. In this post we’ll look at the async coding features of EF.

Asynchronous code execution in .NET has been greatly enhanced by the await-async keywords. If you are not sure what they are about you can start here. They can help keeping the available threads busy thereby utilising the CPU resources better. You have probably seen a lot of methods built-into .NET4.5+ whose names end with “Async”, e.g HttpClient.SendAsync or StreamWriter.WriteAsync.

These awaitable asynchronous methods all return a Task or a Task of T. EntityFramework is no exception to the new trend of making the code more responsive and scalable. The async version of some well-known operators such as ToList() are usually available on methods that return something immediately, i.e. the non-deferred LINQ operators.

Demo

Open the Cars demo application we’ve been working on so far in this series. We have the following Index action in CarController.cs at present:

public ActionResult Index()
{
      return View(db.Cars.ToList());
}

As you type “db.Cars.” in the editor you’ll see that there’s a ToListAsync method. You cannot just use that method like…

public ActionResult Index()
{
      return View(db.Cars.ToListAsync());
}

…since it returns a Task of List of Cars and the view is expecting an IEnumerable of Cars. To make the Index method asynchronous we need to transform it as follows:

public async Task<ActionResult> Index()
{
      return View(await db.Cars.ToListAsync());
}

…where Task resides in the System.Threading.Tasks namespace. If you run the application now you should get the list of cars from the database as before. However, the following is happening behind the scenes:

  • Some thread enters the Index action
  • The thread sees the await keyword and lets another thread take over the processing of the awaitable method, i.e. the collection of cars from the database
  • When the awaitable method is finished by another thread then either the original thread or a new thread finishes the Index method

Check out the above link for a more detailed treatment of the async-await keywords.

Similarly the Details method can be rewritten as follows:

public async Task<ActionResult> Details(int? id)
{
          if (id == null)
          {
              return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
          }
          Car car = await db.Cars.FindAsync(id);
          if (car == null)
          {
              return HttpNotFound();
          }
          return View(car);
}

Note the FindAsync method which as the asynchronous version of Find in EF and returns a Task of Car.

The POST Create method can be made asynchronous by calling the async version of SaveChanges, i.e. SaveChangesAsync:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create([Bind(Include="Id,Make,Category")] Car car)
{
          if (ModelState.IsValid)
          {
              db.Cars.Add(car);
              await db.SaveChangesAsync();
              return RedirectToAction("Index");
          }

          return View(car);
}

In case you’d like to generate asynchronous action methods when inserting a new controller then you can check the following option:

Create async action methods in scaffolding

The templating engine will generate code similar to how our existing code was transformed above.

Logging

The DbContext object has a property called Database which in turn has a property called Log. The Log property is of type Action of String, i.e. you can assign a void method to it that accepts a string. The string parameter includes the actual SQL statements sent to the database.

In CarsDbContext.cs we have an empty constructor at present:

public CarsDbContext() : base("DefaultConnection")
{
            
}

Add the following code to the body of the constructor:

Database.Log = statements => Debug.WriteLine(statements);

Run the application and navigate to /cars. You should see a couple of SQL statements in the Output window related to the retrieval of Cars from the data store:

EntityFramework logging to output window

The first time a query is run you’ll see one or more statements related to data migration, but they won’t be run on subsequent queries.

You can of course assign a more complicated logging delegate to the Log property: log to the database, a file, GrayLog etc.

In the next post, which will end this introductory series on EF, we’ll look at how to update schemas.

You can view all posts related to data storage on this blog here.

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Elliot Balynn's Blog

A directory of wonderful thoughts

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

Bite-size insight on Cyber Security for the not too technical.

%d bloggers like this: