This content relates to a pre-release version of Entity Framework (EF6)
For more information, see Future Versions
This walkthrough will get you started with creating an application that makes use of the Entity Framework’s new asynchronous methods, which were first introduced in the EF6 alpha1 release. While not all applications may benefit from asynchrony, it can be used to improve client responsiveness and server scalability when handling long-running, network- or IO-bound tasks.
If you are unfamiliar with the Entity Framework, you can find plenty of Getting Started documentation on our website. This walkthrough also assumes familiarity with the asynchronous programming model, and with the new async and await keywords. For an overview what’s new with async in .NET 4.5, you may also want to read Brandon Bray’s primer on these changes.
For simplicity’s sake, we’ll begin by setting-up a C# console application for managing a database of questions and answers, called “AnswersDB.” Each question can have multiple answers, and each answer belongs to only one question. We’ll be using EF’s Code First workflow to create our model and generate the database.
Here is the model that powers this Q&A service:
public class Question
{
public int Id { get; set; }
public string Content { get; set; }
public virtual ICollection<Answer> Answers { get; set; }
}
public class Answer
{
public int Id { get; set; }
public string Content { get; set; }
public virtual Question Question { get; set; }
}
In addition to the two POCO models, we’ll add a class for handling the database operations:
public class AnswersContext : DbContext
{
public DbSet<Question> Questions { get; set; }
public DbSet<Answer> Answers { get; set; }
}
Finally, we can apply our model to our database by simply pressing F5. (Alternatively, for more fine-grained control we could use Code First Migrations.)
Let’s start with a (synchronous) program for inputting and printing our Q&A data:
static void Main(string[] args)
{
DoWork();
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
static void DoWork()
{
Console.WriteLine("===Please enter five Questions and Answers===");
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Enter the Question:");
string question = Console.ReadLine();
Console.WriteLine("Enter the Answer:");
string answer = Console.ReadLine();
Console.WriteLine("Saving entry...");
SaveInput(question, answer);
}
PrintQuestions();
}
private static void SaveInput(string question, string answer)
{
using (var ctx = new AnswersContext())
{
ctx.Questions.Add(new Question()
{
Content = question,
Answers = new List<Answer> { new Answer { Content = answer } }
});
ctx.SaveChanges();
}
}
private static void PrintQuestions()
{
using (var ctx = new AnswersContext())
{
foreach (var q in ctx.Questions)
{
Console.WriteLine(q.Content);
foreach (var a in q.Answers)
{
Console.WriteLine(" -" + a.Content);
}
}
}
}
This code asks for input of questions and answers, saves each pair, and prints all of the stored pairs at the end.
Now that we have our program up and running, we can begin making use of the new async and await keywords. Let’s start with the two helper methods which save and fetch the data, respectively.
private static async Task SaveInput(string question, string answer)
{
using (var ctx = new AnswersContext())
{
ctx.Questions.Add(new Question()
{
Content = question,
Answers = new List<Answer> { new Answer { Content = answer } }
});
await ctx.SaveChangesAsync();
}
}
private static async Task PrintQuestions()
{
using (var ctx = new AnswersContext())
{
await ctx.Questions.Include(q => q.Answers).ForEachAsync(q =>
{
Console.WriteLine(q.Content);
foreach (var a in q.Answers)
{
Console.WriteLine(" -" + a.Content);
}
});
}
}
Instead of calling SaveChanges, we simply await on its async counterpart, SaveChangesAsync. For the most part, EF’s asynchronous methods can be identified using this naming pattern. (For example, Find becomes FindAsync, ToList becomes ToListAsync, and so on.)
Since there is no async equivalent of a foreach statement, we make use of the ForEachAsync extension method. We also make use of eager-loading with a call to Include, which tells the query to include the related “Answers” objects. Both of these additions allow us to query for these objects asynchronously and enumerate through the results.
For a comprehensive list of available extension methods in the System.Data.Entity namespace, refer to the IQueryableExtensions class. You’ll also need to add “using System.Data.Entity” to your using statements.
Now let’s look at how we call these methods from our Main method. Keep in mind that the compiler will raise an error if it encounters an async “Main” method, so instead we’ll turn DoWork into a “fire-and-forget” (async void) method. More on return types can be found in the Async Return Types MSDN topic.
static void Main(string[] args)
{
DoWorkAsync().Wait();
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
private static async Task DoWorkAsync()
{
Console.WriteLine("===Please enter five Questions and Answers===");
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Enter the Question:");
string question = Console.ReadLine();
Console.WriteLine("Enter the Answer:");
string answer = Console.ReadLine();
Console.WriteLine("Saving entry...");
await SaveInput(question, answer);
}
await PrintQuestions();
}
With that, our methods will now run asynchronously!
We now saw how easy it is to make use of EF’s asynchronous methods. Although the advantages of async may not be very apparent with a simple console app, these same strategies can be applied in situations where long-running or network-bound activities might otherwise block the application, or cause a large number of threads to increase the memory footprint.
As mentioned previously, Brandon Bray’s async primer goes into detail on the changes in .NET 4.5. For more resources, you should take a look at the Asynchronous File I/O and Asynchronous Programming with Async and Await pages in the MSDN Library, or the Visual Studio Asynchronous Programming section of Visual Studio’s documentation site. ASP.NET MVC4 also comes with async support that works well with EF6 async methods.
Let us know how EF’s new async support works for you!