Monthly Archives: July 2013

Async Query and Batch with Entity Framework

When you’re working with WPF or Windows forms one of the common issues that crops up is cross threading in your viewmodels. The following is a simple solution that wraps up a BackgroundWorker in some standalone classes that can be used with your DbContext. The nice thing about this solution is it doesn’t require you to inherit any classes and you can stick the code in yuo project where you feel it works best.

Asynchronous Queries

Here’s how we might use async queries to tidy up our viewmodels a bit and still retain that synchronization context from the Dispatcher so we don’t end up with annoying cross thread issues when updating properties on our viewmodels.

Usage

AsyncQuery<DataContext>.List<Company>(results =>
{
    this.Companies = new ObservableCollection<Company>(results);
});

AsyncQuery requires the DbContext as a type, and the type of model to supply to the static method you want to call. In this case, we want a list of all companies in our database, our callback transforms this to the often needed ObservableCollection in WPF. Of course, you can do whatever you want with it. AsyncQuery will dispose of your context, so be careful when using lazy loaded properties. You’ll want to use the overloads for eager loading if that’s the case.

Code

public static class AsyncQuery<T> where T : DbContext, new()
{
   /// <summary>
   /// Find an entity by type and id asynchronously
   /// </summary>
   public static void Find<TModel>(object[] keyValues, Action<TModel> callback, Action<Exception> exceptionCallback = null) where TModel : class
   {
       ExecuteAsync(() =>
       {
           using (var context = new T())
           {
               return context.Set<TModel>().Find(keyValues);
           }
       }, callback, exceptionCallback);
   }

   /// <summary>
   /// Gets all entities of a given type asynchronously
   /// </summary>
   public static void List<TModel>(Action<IList<TModel>> callback, Action<Exception> exceptionCallback = null) where TModel : class
   {
       ExecuteAsync(() =>
       {
           using (var context = new T())
           {
               return context.Set<TModel>().ToList();
           }
       }, callback, exceptionCallback);
   }

   /// <summary>
   /// Gets all entities of a given type asynchronously
   /// </summary>
   public static void List<TModel, TProperty>(Expression<Func<TModel, TProperty>> includePath, Action<IList<TModel>> callback, Action<Exception> exceptionCallback = null) where TModel : class
   {
       ExecuteAsync(() =>
       {
           using (var context = new T())
           {
               return context.Set<TModel>().Include(includePath).ToList();
           }
       }, callback, exceptionCallback);
   }

   /// <summary>
   /// Get a list of filtered entities asynchronously
   /// </summary>
   public static void Where<TModel>(Func<TModel, bool> predicate, Action<IEnumerable<TModel>> callback, Action<Exception> exceptionCallback = null) where TModel : class
   {
       ExecuteAsync(() =>
       {
           using (var context = new T())
           {
               return context.Set<TModel>().Where<TModel>(predicate);
           }
       }, callback, exceptionCallback);
   }

   /// <summary>
   /// Get a list of filtered entities asynchronously
   /// </summary>
   public static void Where<TModel, TProperty>(Func<TModel, bool> predicate, Expression<Func<TModel, TProperty>> includePath, Action<IEnumerable<TModel>> callback, Action<Exception> exceptionCallback = null) where TModel : class
   {
       ExecuteAsync(() =>
       {
           using (var context = new T())
           {
               return context.Set<TModel>().Include(includePath).Where<TModel>(predicate);
           }
       }, callback, exceptionCallback);
   }

   /// <summary>
   /// Execute a background task that performs its callback on the calling thread to avoid invoke.
   /// Requires the calling thread to have a synchronization context such as a WPF application.
   /// </summary>
   /// <typeparam name="TModel">The type of the result</typeparam>
   /// <param name="task">The method to execute async</param>
   /// <param name="callback">The callback</param>
   private static void ExecuteAsync<TModel>(Func<TModel> task, Action<TModel> callback, Action<Exception> exceptionCallback = null)
   {
       var worker = new BackgroundWorker();
       worker.DoWork += (s, e) =>
       {
           e.Result = task();
       };
       worker.RunWorkerCompleted += (s, e) =>
       {
           if (e.Error == null && callback != null)
               callback((TModel)e.Result);
           else if (e.Error != null && exceptionCallback != null)
               exceptionCallback(e.Error);
       };
       worker.RunWorkerAsync();
   }
}

Asynchronous batches

Sometimes you really need to batch several updates together without having to chain the actions together.

Usage

var batch = AsyncBatch<DataContext>.Create();
batch.Queue(c => c.Companies.Add(new Company() { Name = "Bobs Burgers" }));
batch.Queue(c => c.Companies.Add(new Company() { Name = "Taco Johns" }));
batch.Queue(c => c.Companies.Add(new Company() { Name = "Wendys" }));
batch.Queue(c => c.Companies.Add(new Company() { Name = "Super Burger" }));
batch.Queue(c => c.Companies.Add(new Company() { Name = "Nacho Mamas" }));
batch.Queue(c => c.SaveChanges());

batch.ExecuteAsync(() =>
{
    using (var context = new DataContext())
    {
        this.Companies = context.Companies.ToList();
    }
});

The AsyncBatch class will create the instance of your DbContext for you, and automatically dispose of it after the batch completes. You can queue up any actions you need, then call ExecuteAsync(Action) to handle the completion. Since this executes using a BackgroundWorker, it saves you from having to call Dispatcher.Invoke when you update view model properties.

Since the batch won’t return any values for you, this is really only useful when doing batch updates, inserts, or deletes.

Code

public class AsyncBatch<T> where T : DbContext, new()
{
    /// <summary>
    /// Creates a new instance of <see cref="AsyncBatch"/> with the given DbContext
    /// </summary>
    public static AsyncBatch<T> Create()
    {
        var unitOfWork = new AsyncBatch<T>();
        unitOfWork.context = new T();
        unitOfWork.actions = new List<Expression<Action<T>>>();
        return unitOfWork;
    }

    /// <summary>
    /// Execute all actions that have been queued asynchronously
    /// </summary>
    /// <param name="callback">The method to execute when all actions have been completed</param>
    /// <param name="exceptionCallback">The method to exeute if there was an unhandled exception</param>
    public void ExecuteAsync(Action callback, Action<Exception> exceptionCallback = null)
    {
        var worker = new BackgroundWorker();
        worker.DoWork += (s, e) =>
        {
            foreach (var action in this.actions)
                action.Compile()(this.context);
        };
        worker.RunWorkerCompleted += (s, e) =>
        {
            context.Dispose();

            if (e.Error == null && callback != null)
                callback();
            else if (e.Error != null && exceptionCallback != null)
                exceptionCallback(e.Error);
        };
        worker.RunWorkerAsync();
    }

    /// <summary>
    /// Queue an action to be executed asynchronously
    /// </summary>
    /// <param name="action">The action</param>
    public AsyncBatch<T> Queue(Expression<Action<T>> action)
    {
        actions.Add(action);
        return this;
    }

    private List<Expression<Action<T>>> actions;
    private T context;
}

Oktoberfest 2012

This is a video board created for DuClaw Brewing Company to display what’s on tap at the Maryland Brewer’s Oktoberfest. Created to run on Xbox 360 or Windows 7 connected to a big ass Flat Panel television and a set of very loud speakers. The board also plays promotional videos on a set schedule and has a few more animations and effects not shown in this clip.

The board actually runs on 3 different screens all with their own content, beer selection, videos, etc. We wrote the original for Oktoberfest 2009 and it gets updated each year. It’s pretty much a giant video game written with XNA and C#.

You’re gonna want to crank the sound for this. It’s OK, I’ll wait. Done?

This is a demo of what happens on screen when you change the beer selection with the controller.