Query Application Block 4.1
The Query Application Block takes the Data Access layer to the next level providing a consistent interface to data storage no matter how or where it is stored. Where the DAAB gives developers a provider model to RDBMS data storage giving independence from the type of RDBMS in use, the Query Application Block gives developers a provider model for queries
to data storage from a variety of different sources and source types using the features of the Enterprise Library 4.1. The Query Application Block interfaces to the DAAB for data stored in relational databases but can also be configured to query data from XML Files and WCF Services. The QAB is designed for two-way data storage, reading and writing to all supported data storage types. All configuration of such queries naturally uses the Enterprise Library Configuration Console.
In essence the QAB is similar to the Entity Framework
, bringing such features to the Enterprise Library. One difference is that the QAB uses DataSets
as the Data Transfer Object type (DTO) and has no mapping facility to convert between DataSets and a business Domain Model. The next stage to providing full Object Relational Mapping (ORM)
between a business Domain Model
and a data store is to combine with the Mapping Application Block
that interfaces to the QAB providing that conversion through configuration. Thus the QAB and the MAB combine together, along with the Configuration Console, to form a full ORM tool.Note:
There was much debate over my use of the DataSet
rather than the slimmer DataTable
for the Data Transfer Object
type, especially as multiple table handling is quite rare. However, I felt the additional flexibility provided within a DataSet, especially for use with custom commands, outweighed the overhead.
The developer is not limited to the providers out-of-the-box but can extend the block by adding providers of their own in the normal Enterprise Library extensible fashion.
The following are the main features associated with the Query Application Block:
- Complete independence from the type of data store be-it relational database, XML file or web service.
- Consistent interface to your data through DataSets no matter where it orginated from or is to be stored away to.
- Configuration facility for Queries and Parameters where a query is a call to a data store and a parameter is data that is needed by that call.
- You can use either the stand-alone Enterprise Library Configuration Console or the Visual Studio integrated Console to manage all Query Application Block settings.
- If you need to manage data from a storage type not currently supported then you can extend the application block by creating custom query providers and custom parameter providers
- If you need to perform complex commands against a data store e.g. to process BLOB's then there is a custom command feature to enable you to intervene when you need to.
- Management and monitoring features include Windows Active Directory Group Policy integration and instrumentation features such as Performance Counters, Windows EventLog logging and WMI events.
- Dependency Injection support. The Query Application Block integrates with Unity v1.2 for the creation of all its objects.
If you need convincing as to why you would use this block, have a look at the following reasons:
- You need to query data from multiple sources and different types. e.g. configuration from XML, external feeds through services and business data from an RDBMS. The Query Access Block can handle all these types of data store with a simple DataSet-based interface.
- You want to treat all data the same no matter where it comes from and in what format. Your application code will manage all its data through DataSets.
- You think you might need to change some of your data sources on-the-fly without having to re-compile and re-install assemblies each time. Through configuration the Query Application Block allows you to change the source or even type of data source and provided that the overall command call (e.g. number and order of parameters) does not change there is no need for any changes to code.
- Even though you use the Data Access Application Block (DAAB) you still find yourself writing a lot of code to create all the queries that you need in your DAL. The Query Application Block handles the creation and execution of queries through configuration, managing all commands and associated parameters.
- You have been given a very tight deadline and you have a complete Data Access Layer to produce. The Query access block can handle all DAL communication through configuration alone.
- You find you need to perform some special non-standard processing on a particular query then the QAB provides the Custom Command interface for just such a purpose whilst still doing most of the work for you.
A Quick Code Sample
The following code sample shows the basic function of the block, how to get data with a simple query that takes no parameters:
// execute a query with a configured name of "Read Data" that takes no parameters and reads data from a data store returning the results as a DataSet
DataSet ds = QueryFactory.CreateQuery("Read Data").ExecuteForRead();
This next code sample shows how to execute a read query that takes a single parameter:
// execute a query with a configured name of "Read Data By Id" that takes a single integer parameter with the name of "Id" and value of 27 and reads data from a data store returning the results as a DataSet
IDictionary<string, object> parameters = new Dictionary<string, object>();
DataSet ds = QueryFactory.CreateQuery("Read Data By Id").ExecuteForRead(parameters);
This next code sample shows how to execute a write query that takes 3 parameters:
// execute a query with a configured name of "Write Data" that takes 3 parameters and writes the data away to a data store
IDictionary<string, object> parameters = new Dictionary<string, object>();
This next code sample shows how to execute a write query that takes its parameters from a DataSet:
// execute a query with a configured name of "Write Data from DataSet" that takes a DataSet and writes the data away to a data store
DataSet dataSet = GetDataSetFromGridView();
QueryFactory.CreateQuery("Write Data from DataSet").ExecuteForWrite(dataSet);
Installing the Assemblies
When you build the Query Application Block the assemblies are compiled without a strong name key. If you want to put these assemblies into the GAC then you will need to assign a strong name key to each assembly and recompile (this is not neccessary for any design.dll
assembly). If you use the BuildLibraryAndCopyAssemblies.bat
console script then the assemblies are copied to the EntLibContrib bin
folder. You can reference the assemblies from here for your application however; to use the Configuration console you will need to copy all of the following assemblies to your installation of the Enterprise Library Configuration Console which is usually in C:\Program Files\Microsoft Enterprise Library 4.1 - October 2008\Bin
The Query Application Block 4.1 consists of the following assemblies:
- EntLibContrib.Query.dll - the main assembly for the block
- EntLibContrib.Query.Database.dll - to comply with the rule that all application blocks must be able to work independantly of any other block, the data query provider, which has a dependancy on the Data Access Application Block was separated out to its own assembly.
- EntLibContrib.Query.Configuration.Design.dll - the plug-in interface to the Enterprise Library Configuration Console for the Query Application Block.
- EntLibContrib.Query.Database.Configuration.Design.dll - the plug-in interface to the Enterprise Library Configuration Console for the Query Application Block data query provider.
- EntLibContrib.Common.dll - Common Core code shared between all EntLibContrib extensions
- EntLibContrib.Common.Configuration.Design.dll - Common Configuration Console design code, shared between all EntLibContrib extensions
The QAB is inspired by the ideas in Martin Fowler's
book Patterns of Enterprise Application Architecture
. The Query Application Block implements the DTO, Query Object, Gateway and Plugin patterns as well as the "finder" and "command" objects. I have now complemented the QAB with a Mapping Application Block (MAB) which completes the implementation of PoEAA by adding configurable Object Relational Mapping to a Domain Model.