Introduction
While in the process of working through multiple solutions requiring numerous queries from different, inter-connecting, Domain Contexts, I required a mechanism
of knowing when all the queries had completed.
This is mainly because there was no way of doing an include on the servers, because the data was located in physically different databases,
and references were added on the client. This made it even more important as Navigation properties were used for binding on the user controls,
and as such had to be locked until such time as the data was available.
MultiSyncQueryLoader
MultiSyncQueryLoader
is the wrapping class that is responsible for the notification that all the queries were successfully completed.
It has been written in a manner that will allow the same mechanism as you would use for a normal query to a Domain Context, but using the AddQuery
method instead.
Just so that I give credit where it is due, my colleague Robin Marshall
added in the default context and LoadBehaviour
properties to allow simplified queries from the Domain Context.
There are two ways of ultimately querying the data using the loader: asynchronous and synchronous (or at least asynchronous but in sequential order).
The RunSync
method was designed for the scenario where a callback of one query required that data be loaded by a query, before that callback was actually run.
The RunAsync
method will be more typically used by the day-to-day queries that will be run in a Silverlight / Entity Framework environment.
This is designed to fire all the queries simultaneously to the relevant services, and await the responses.
Each of the queries will notify via the Completed
event when all the queries have finished loading.
DomainContextQuery<T>
The DomainContextQuery<T>
generic is where all the magic happens. Its job is to run the EntityQuery
against the associated DomainContext
and notify the initiator that it has completed.
The Run(Action)
method is responsible for running the synchronous calls, as we do not need to pass in a userstate variable for the listening invoker to know what
DomainContextQuery
was actually being run.
The Run(Action<object>)
method, however, is required for the asynchronous calls. This is so that we can extend the method to use
the DomainContextQuery
that invoked it, should it be required.
Each method will mark the DomainContextQuery
as Complete
so that it is quick for the MultiSyncQueryLoader
to check if there are any outstanding queries,
and if not, fire the Completed
event.
Using the Code
To explain the use of the code, I will use an excerpt from the attached demo solution:
MultiSyncQueryLoader loader = new MultiSyncQueryLoader(context, LoadBehavior.MergeIntoCurrent);
loader.AddQuery(context.GetCustomersQuery(), (callback) => CustomersLoaded = true);
loader.AddQuery(context.GetCategoriesQuery(), (callback) => CategoriesLoaded = true);
loader.AddQuery(context.GetCustomerDemographicsQuery(), (callback) => CustomerDemographicsLoaded = true);
loader.Completed += () => CompleteLoaded = true;
loader.RunAsync();
To utilise the code, just create an instance of the query loader (use a default domain context and load behaviour if required).
Add each query using the method. The AddQuery
method has been designed in a way that will not interfere with the original code.
For example, before the query loader, a load from a Domain Context could have appeared as follows:
context.Load(context.GetCustomersQuery(), LoadBehavior.MergeIntoCurrent, callback => { }, null)
Whereas now with the AddQuery
method (and no default context specified):
loader.AddQuery(context,context.GetCustomersQuery(), LoadBehavior.MergeIntoCurrent, callback => { } , null);
Continued Development
Any future development on this project will be maintained on Github. I will always attempt to place an up-to-date version on the article, but its always best to check.