Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Auto-SQL DataGrid component. Part I: Non-editable version

0.00/5 (No votes)
8 Aug 2005 1  
ASQLDataGrid is a useful component when working with RDBMS applications. It is capable to automatically construct and execute SQL statements based on its properties.

What is Auto SQL DataGrid?

The Auto SQL DataGrid is capable to automatically build the SQL statements using to populate, insert, update and delete the data from/into the database behind the datagrid by using only information of the properties of the datagrid and its columns. In optimal cases, you have only to name the datagrid�s ID after the DB table name and the DataField of each column with the correct name of the DB column behind it and the ASQLDataGrid will do all the magic for you. It also provides a simple and intuitive programming interface to alter the default behavior to deal with more complicated cases like the one when you have to join two or more DB tables in the Select statement. In this 1st article of the series, I will introduce the non-editable version of the ASQLDataGrid, while the 2nd article will complete the class with insert, update and delete features. You should be familiar with the basics of the Relational Database Management Systems (RDBMS) and the syntaxes of SQL statements in order to work with the ASQLDataGrid component.

The CmdButtonForm and the CmdButton classes

You can check the details of how to use the CmdButtonForm class in my previous article here. Shortly, it provides the class-library level mechanism of handling (multiple) submit button on a form by using hidden tags. You should inherit your own WebForm from this class like this:
public class WebForm1 :NTM.Controls.CmdButtonForm
The CmdButton class is the accompanying class to the CmdButtonForm. It has two public properties: Cmd which specifies the command to execute (Populate, Save, etc) and the Param for the parameter string (e.g. the ID of the target datagrid). In the sample project, I added the Populate button to the web form like this:
<ntm:CmdButton id="btPopEmployees" runat="server" Cmd="DG_POP" Param="DG_Employees" Text="Populate" Width="73"></ntm:CmdButton>

The ASQLDataGridCmdExecutor class

The ASQLCmdExecutor property of the ASQLDataGrid specifies the object to handle the commands and it should be instantiated from the ASQLDataGridCmdExecutor class or from a class inherited from it. If you don�t assign any value to this property, the ASQLDataGrid class will create a default ASQLDataGridCmdExecutor object and let it handle the (standard) commands:
protected override void OnLoad(EventArgs e)
{
...
            if (this._ASQLCmdExecutor == null)
            {
                //Create and use a default command executor

                this._ASQLCmdExecutor = new ASQLDataGridCmdExecutor();
            }
            _ASQLCmdExecutor.ExecuteCmd(this, Command, CommandParam);
...
}
Besides the standard commands like DG_POP for populating the data from the DB, you can define any command and write your on command executor to handle it. For instance you may want to have a Delete All button. First, you should add the command button to your web form:
<ntm:cmdbutton id="btDelAllEmployees" runat="server" Cmd="DG_DELALL" Param="DG_Employees" Text="Delete All" Width="73"></ntm:cmdbutton>
You can inherit your own command executor class from the ASQLDataGridCmdExecutor as shown in the following code:
public class MyCmdExecutor : ASQLDataGridCmdExecutor
{
    public override void ExecuteCmd(ASQLDataGrid dg, string Cmd, string CmdParams)
    {
        if (Cmd.Equals("DG_DELALL"))
        {                           
            //Write you own code to here

            ...
        }
        else
            base. ExecuteCmd (dg, Cmd, CmdParams);
    }
}
Now on the WebForm, you can assign your newly developed command executor to the DataGrid like this:
private void Page_Load(object sender, System.EventArgs e)
{
    ...
    DG_Employees.ASQLCmdExecutor = new MyCmdExecutor ();                                              
    ...
}

The ASQLDataGridStatBuilder class

Here comes the meat of the component � the SQL statement (auto) builder class. Just like the command executor, if you don�t specify any value to the ASQLBuilder property of the ASQLDataGrid, it will create a default ASQLDataGridStatBuilder instance and use it to construct the SQL statements. Let�s see what does this default ASQLDataGridStatBuilder object do. Here is how the BuildSelect method of it (which returns the whole Select statement) looks like:
public virtual string BuildSelect(ASQLDataGrid dg)
{
    return  "select " + SEL_BuildListOfColumns(dg) + " from " + SEL_BuildFromClause(dg) + SEL_BuildWhereClause(dg)
                + SEL_BuildGroupByClause(dg) + SEL_BuildHavingClause(dg) + SEL_BuildOrderByClause(dg);
}

The statement builder atomized the select statement into smaller clauses: the List of columns, the From and the Where condition, the GroupBy, the Having and the OrderBy clauses. By default the Where,GroupBy,Having and the OrderBy clauses returned empty strings. The From clause is extracts from the ID of the DataGrid by taking all the characters after the 1st underline character in it (if exists). It means when working with DB table name Employees, we should assign to our ASQLDataGrid with ID something like DG_Employees for instance. The SEL_BuildListOfColumns method concatenates all the strings returned by the GetDBColumnName method for each column with the comma separators between the tags while the GetDBColumnName in its turn returns the DataField or DataTextField of the BoundColumn/HyperLinkColumn. If you are using TemplateColumns you should write your own Statement Builder and specify the correct DB column as I will show you later. Note that I implemented the statement builder class following the syntax of the select statement (and other statements in the 2nd article) of MS Trans-SQL. You may have to alter it and implement your own version of statement builder to suit your needs (e.g. working with other RDBMS).

The sample project works with the Employees table from the MS NorthWind database. To have a datagrid which will show you the list of the current employees, all you have to do is to have an ASQLDataGrid with ID = DG_Employees and assign the DataField property of each BoundColumn to the corresponding DB column�s name (EmployeeID, TitleOfCourtesy, FirstName, LastName, BirthDate, Address and ReportsTo for instance). The Statement Builder will help us to construct the Select statement which will be:

select EmployeeID, TitleOfCourtesy, FirstName, LastName, BirthDate, Address, ReportsTo from Employee

Add the Populate command button as I showed earlier and that�s it � we have a working datagrid application. Very simple to use, isn�t it? Now we will see how we can alter this default statement builder to improve our sample application. By now, the ReportsTo column contains EmployeeIDs (of whom the employee has to report to) and we want to display the names of the persons instead of the IDs. To do it, we have to join the Employee DB table to itself in the select statement. So we inherit our own Statement Builder from the ASQLDataGridStatBuilder class like this:

    
public class ASQLBuilder1 : ASQLDataGridStatBuilder
{
    public override string  SEL_BuildFromClause(ASQLDataGrid dg)
    {
        return "Employees E1 left join Employees E2 on E1.ReportsTo = E2.EmployeeID";
    }
    public override string GetDBColumnName(TypeOfSQLStatement stat, ASQLDataGrid dg, int ColumnIndex)
    {
        if (ColumnIndex == 6)
        {
            //ReportsTo

            if (stat == TypeOfSQLStatement.Select)
            {
                return "(E2.FirstName + ' ' + E2.LastName) as ReportsTo";
            }
            else
                return base.GetDBColumnName(stat, dg, ColumnIndex);
        }
        else
        {
            if (stat == TypeOfSQLStatement.Select)
            {
                //Qualifying all the column with the (E1) table name

                string DBColName  = base.GetDBColumnName(stat, dg, ColumnIndex);
                if (DBColName.Length>0)
                    return "E1." + DBColName;
                else
                    return "";
            }
            else
                return base.GetDBColumnName(stat, dg, ColumnIndex);
        }
    } 
As you see, we override the SEL_BuildFromClause method of the Statement Builder and now it returns the join of two Employee tables. Also, we have to qualify all the column names with the table name and displaying the ReportsTo person name instead of the ID by overriding the GetDBColumnName method as shown. And now, the newly developed Statement Builder will help us to construct the final Select statement:
select E1.EmployeeID,E1.TitleOfCourtesy,E1.FirstName,E1.LastName,E1.BirthDate,E1.Address,(E2.FirstName + ' ' + E2.LastName) as ReportsTo 
        from Employees E1 left join Employees E2 on E1.ReportsTo = E2.EmployeeID
Practically, by overriding suitable method(s) of the ASQLDataGridStatBuilder class, you can have a Statement Builder which is capable to build very complicated SQL statements necessary to your real applications. After writing your own Statement Builder, don�t forget to assign it to the DataGrid in a similar way as I showed with the Command Executor earlierly:
private void Page_Load(object sender, System.EventArgs e)
{
    ...
    DG_Employees.ASQLBuilder = new ASQLBuilder1();
    ...
}
The final note is that you can even use one Statement Builder to serve multiple ASQLDataGrid. Sometimes it can reduce the developing time.

Conclusion

The ASQLDataGrid presented here is a useful component when working with RDBMSs. It can reduce the time of development; help you to focus on the real business logic instead of dealing with SQL syntaxes. I will complete this class with the auto-construction of Insert, Update and Delete statements in the 2nd article.

Happy programming!

History

  • 08, August 2005 - Initial version.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here