CQRS, Implementing the Query Pattern

I have recently started reading about the Command and Query Responsibility Separation (CQRS) pattern, which is a pattern that can be applied to the architecture of a system, with the emphasise on treating requests that query the data differently to requests that perform a command.

To simplify this, if we think about the basic CRUD operations, the query separation would be for all Read operations and the command separation would cover Create, Update and Delete operations.  The overall idea is for the architecture of the system to treat command requests and query requests differently.

The operations performed on a typical application may see about 80% of all requests solely being for read only requests to display some data to the end user.  One of the aims of CQRS is that it looks to simplify the retrieval of such data, implying there is no need to always navigate through all layers / components of a system, just to collect some data from the database and return it to display.  Instead presentation layer itself can be responsible for requesting such data directly from the database.

This post is going to look at how this could be achieved using jQuery and WCF data services, which will be used to expose the entities within an entity framework model directly to the presentation layer.

Will start by looking at the WCF Data Service.  A WCF Data Service allows an Entity Framework (EF) model to be exposed and accessed using a RESTFul interface by simply consuming the Data service in a calling application.  To make things simpler to understand lets jump straight into the code.

public class WcfDataService : DataService<CustomContext>
{
	public static void InitializeService(DataServiceConfiguration config)
	{
		config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
		config.SetEntitySetPageSize("*", 5);
		config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
	}
}

The key part to a WCF data service is setting the type the data service is using, in this case DataService<CustomContext>.  The type that is specified is the EF model context.  Having set the type there is some further configuration, which is specified in the InitializeService method.

Probably the most important configuration setting is the SetEntitySetAccessRule property.  The purpose of this property is to specify the level of access you provide to any application that makes use of this service.  This can be readonly access or provide the ability to manipulate the data within your model by allowing create, update and delete commands to be run against the data service.  You can use this setting to set different access rules for the different entities your model exposes by setting the name input to the name of one of your entities , or you can specify that all use the same rule by setting the name input to *. The following code segment illustrates applying the read only access right to all entities in the model. This nicely allows us to enforce the rule that using this data service as our implementation of the query command pattern, data can only be read using this service.

config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);

There are further configuration settings you can impose on your data service, such as limiting the maximum number of rows returned from one or all entities, which can prevent potentially large data packets being sent over the wire.  The follwing example ensures that a data set only ever returns at a maximum 10 rows.

config.SetEntitySetPageSize("*", 10);

You can also enforce rules on the data being returned by applying QueryInterceptors to an entity.  A QueryInterceptor can be used to restrict what data is returned when querying an entity.  The example below applys a QueryInterceptor to the Car entity to only ever return cars that have a vehicle make of Ford.

[QueryInterceptor("Car")]
public Expression<Func<Car, bool>> CarDefaultFilter()
{
	return (Car c) => c.Vehicle_Make == "Ford";
}

A more practical use for a QueryInterceptor would be to restrict the data returned for the given logged in user. This can prevent sensitive data ever being accessed by anyone.

The examples above have explained a few simple steps you can take to expose an Entity framework model over the web.  Now we will cover consuming the data.

By adding a service reference to the WCF data service through Visual Studio in the client application, the EF model container proxy can be consumed.  By creating a new instance of the EF model container, including the URI of the WCF data service location within the constructor, you can then start using data context as if it was held locally, by executing LINQ queries against the context.  The example illustrates the above.

public JsonResult GetData(),
{
	var uri = new Uri("http://localhost.:44186/WcfDataService.svc/");
	var context = new CarEntities(uri);
	var query = (from car in context.Code44
	select new { VMake = car.Vehicle_Make }).ToList();
	return Json(query, JsonRequestBehavior.AllowGet);
}

When executing LINQ statements against the data context under the hood Visual Studio converts these LINQ statements into RESTFul URI’s which are then submitted against the WCF data service.  Using a tool such as fiddler, you can see what is actually going on when running a LINQ statement.