XQuiSoft Data is an open source component for database neutral .NET applications. It is part of the XQuiSoft application framework, which is entirely open source. The source download includes the demo business component and demo web site. All the source code in this article can be found in the download. You can get the latest version of the project here.
This data component has a dependency on another open source project in the xquisoft framework, the xquisoft provider component. It is basically an implementation of the provider pattern for the 1.1 framework similar to that in the 2.0 framework. This open source project can be found here.
In this article, I will show examples of how to use the XQuiSoft Data component from the business tier of your application. The downloadable source will include a sample web project that calls these components, which I will only briefly discuss.
First of all, make sure you download the correct version. The latest version at the time of this article is 2.2.50727.0. Earlier versions show a different way to use the component that may be obsolete in the future. Future versions will also include the demo projects. To get the required xqs-provider reference, you can either download the XQuiSoft Data binaries which include it in compiled form, or you can download the source from the xqs-provider downloads area.
The source download for
XQuiSoft.Datacontains three projects. The first is the Data class library source, which compiles to XQuiSoft.Data.dll. The second is a demo library that contains most of the code snippets in this article, which compiles to XQuiSoft.Data.Demo.dll. The third project is a web application project showing usage of the code in the sample code below.
- Create a new solution file in the folder above these projects, and add each project to it. I have a different solution that contains other core xquisoft projects, and I could not include it.
- Update the web.config of the web application. You must update the database connection string to a database of which you have an account with create table access. This access is required for the installer. If you prefer to run the scripts yourself feel free, then all the user in the connection string needs to have access to do is run the stored procedures created by the script.
- The solution should now run / debug normally. The first time you run it, set the start page as Install.aspx. Then navigate to the EmployeeList.aspx page to edit records.
The goal of this demo is to demonstrate how to design your business layer code. The user interface is bare minimum in appearance.
Ease of use: You don't have to worry about opening connections, creating commands, or disposing of resources such as data readers. You just have to know which command you want to call, and pass the command the appropriate parameter values.
Easy to learn: The method names on the supplied classes correspond to method names in the base .NET Framework. This should make it easy to upgrade your current code to use this component.
Extensibility: The data component is based on the provider pattern. This means that the
DataManagerclass delegates the actual writing call to one or more configured providers (implementations) that derive from the base
DataProviderclass. Each provider defines the type of database that it interacts with, and how to fulfill database commands. Currently there is a built in
The first thing you need to do is add some configuration required by the data component. The first portion tells the framework where to load the class that will handle the next custom configuration section. There can be only one '
configSections' tag in your application configuration. So if you have other components with custom configuration sections, merge those with this one.
<section name= "DataManager" type="XQuiSoft.Data.DataManagerConfiguration,
The next part you need is the configuration section that defines all your database connections, which was just described in the '
connectionString="Password=pw;Persist Security Info=True;
;Initial Catalog=DATABASENAME;Data Source=SERVERNAME\INSTANCENAME" />
connectionString="Password=pw;Persist Security Info=True;
Initial Catalog=DATABASENAME;Data Source=SERVERNAME\INSTANCENAME" />
The providers node contains child nodes for each database connection you want to configure. The type attribute is the database implementation provider that represents the type of database you wish to connect to. In the case of a built in type, you really don't need the full assembly name. In this case, "
XQuiSoft.Data.SqlClient.SqlDataProvider" would have been sufficient. The provider component will search the executing assembly for the specified type if the assembly is not specified. The
connectionStringattribute must be valid for the database type you are using.
Notice that there are two attributes that can be on the
DataManagernode. You can either have a '
defaultProvider' which equals one of the names of the child nodes, or you can have a '
defaultProviderAppSettingName' which equals a setting name in the app settings node. The value of that setting must equal one of the provider names in the child nodes.
<add key="ENVCODE" value="Development" />
The reason for doing this is so you can keep your web.config identical in all deployed environments. Then each environment can have a separate Environment.config file that has a value for "
ENVCODE". That file should look identical to the
appSettingsnode above, except without the file attribute specified.
In our sample application, we are going to view and edit employees only. This is just to keep it simple. So the first thing we need to do is define our custom entity class '
Employee', and a strongly typed collection '
EmployeeCollection' which derives from collection base. This is provided in the download, and there is nothing special about these classes. I'm not going to explain them here.
Concrete Provider Implementation using DataManager
Start with a
staticservice class defining methods required by your application. In our case we need to get employees, save, and delete employees. Next define a base provider class with
abstractmethods of the same signature. Next we need a concrete implementation class for
DbEmployeeProvider. Below is an outline of the class with a few of the method implementations shown for discussion. To see the
EmployeeProviderbase class or the
EmployeeManagerservice class, see the code in the download.
public class DbEmployeeProvider: EmployeeProvider
public override void Initialize(string name,
public override ExecutionResults Install()
public override Employee GetEmployee(int id)
Procedure proc = new Procedure("Demo_GetEmployee");
proc.AddInputParameter("EmployeeID", DbType.Int32, id);
DataFactoryDelegate builder =
EmployeeCollection col = new EmployeeCollection();
dataProvider_.Execute(proc, builder, col);
if (col.Count > 0)
public override EmployeeCollection GetSubOrdinates(int managerID)
public override bool SaveEmployee(Employee item)
Procedure proc = new Procedure("Demo_SaveEmployee");
DbType.Int32, ParameterDirection.InputOutput, item.ID);
proc.AddInputParameter("ManagerID", DbType.Int32, item.ManagerID);
proc.AddInputParameter("FirstName", DbType.AnsiString, item.FirstName);
proc.AddInputParameter("LastName", DbType.AnsiString, item.LastName);
int rows = dataProvider_.ExecuteNonQuery(proc);
Parameter prmID = proc.Parameters.Find("EmployeeID");
item.ID = dataProvider_.GetInt32(prmID.Value);
return (rows > 0);
public override bool DeleteEmployee(int id)
protected virtual void AddEmployee(IList target, IDataRecord record)
Employee item = new Employee();
item.ID = dataProvider_.GetInt32(record, "EmployeeID", -1);
item.ManagerID = dataProvider_.GetInt32(record, "ManagerID", -1);
item.FirstName = dataProvider_.GetString(record, "FirstName");
item.LastName = dataProvider_.GetString(record, "LastName");
Stored procedures can be called by instatiating the
Procedureclass with the required name, adding parameter values, and then calling the appropriate
Executemethod. Note that a procedure parameter name should not include a database provider specific prefix. The data provider will handle adding that, if applicable, before the parameter is passed to ADO.NET. The default
SqlDataManagerprovider class adds a
@ prefix to ADO.NET parameters if it does not already exist.
GetEmployeemethod executes the procedure, then another method
AddEmployeeis passed into the
DataFactoryDelegateparameter of the
Executemethod. This delegate method will be called for each record the data reader returned from the database connection. This method instantiates a new data object instance (in this case class
Employee), populates the properties, and adds the new item to the supplied collection.
SaveEmployeemethod uses a procedure also, but it inserts or updates a record (and does not return any records.) It calls
Procedureinstance filled with parameters. The output parameter defined on the procedure is used to populate the id of the record after the
Provider Model Configuration
In order to use this
EmployeeManagerservice, you'll need to configure it to use the
DbEmployeeProvideras follows. Note you'll have to merge the contents of this new
sectionGroupinto the same
configSectionsnode used to configure
XQuiSoft.Data. Notice the connection name is not specified below. When the
connectionNameis not specified, the
DbEmployeeProvideruses the default
DataProviderdefined in the
DataManagersection of the configuration.
<section name= "EmployeeManager"
type="XQuiSoft.Data.Demo.Data.DbEmployeeProvider, XQuiSoft.Data.Demo" />
If your database is shared so that records are split across databases, you will likely want to specify each of the multiple connections to be used by the
DbEmployeeProvider, or the default connection could be used to execute a query on a main database connection to determine which connection holds the data for a given query. Database sharing design is beyond the scope of this article. However, the
DataManagerdoes support an easy programmatic experience for scenarios that require database sharing.
Application Usage (UI)
Usage of the service classes from the user interface is really simple. First we need a form that can bind to the results. Since
CollectionBase, it implements
IListwhich is what the
DataGridis designed to work with (not just datasets).
EmployeeCollection emps = EmployeeManager.GetSubordinates(mgrId);
DataGrid1.DataSource = emps;
That's it! You can now swap out the
DbEmployeeProviderwith a different implementation, and the user interface code does not have to change, or even be recompiled!
I've convered the basics features and usage of the XQuiSoft Data component. Some of the features are really inherited from the XQuiSoft Provider component, so be sure to check that out too. I would be happy to hear your results in using these components. I didn't cover all the code that you'll see in the demo project. Some of the code is for supporting the provider auto-installation feature. I may discuss that feature in a future article. It is not really necassary in a simple application like this demo, but is very useful in a plugin architecture.
If you start a new project, consider the benefits of XQuiSoft Data. Evaluate it, and see if it fits into your toolbox. It would be great to hear feedback on your evaluation in either case.
- April 27, 2006: Initial submission of article
- April 28, 2006: Added extra download instructions
- June 16, 2009: Updated to use the latest features of
XQuiSoft.Dataintroduced in the last year and a half. This update was way overdue.