Auto-SQL DataGrid 组件第二部分: 功能齐全的版本






4.36/5 (6投票s)
2005 年 8 月 9 日
5分钟阅读

38693

945
ASQLDataGrid 是一个在处理 RDBMS 应用程序时非常实用的组件。它能够根据其属性自动构建和执行 SQL 语句。
引言
在我们系列的第二篇文章中,我们将使我们的 ASQLDataGrid
类可编辑——也就是说,该类将能够自动构建其他 SQL 语句:INSERT
、UPDATE
和 DELETE
。请参阅第一篇文章了解前提。在深入细节之前,让我先介绍一下我们 ASQLDataGrid
类的一些特性。首先,尽管我们的 ASQLDataGrid
是可编辑的,但一次只能编辑一行,即使是新添加的行或现有行。该类的第二个特点是,它将在每行数据上显示按钮(编辑和删除),而不是像其他 DataGrid
示例中那样显示超链接。
CmdButtonColumn 类
CmdButtonColumn
是我在第一篇文章中介绍的 CmdButton
的 DataGrid
列版本。它有四个 public
属性
Cmd
:要执行的命令(例如:DG_NEW
、DG_SAVE
)。ButtonText
:当行处于视图模式时显示的按钮文本。LabelText
:当行处于编辑模式时显示的标签文本。PreStatement
:在命令执行之前执行的 JavaScript 代码。它用于在删除行之前添加确认。必要的 JavaScript 在DataGrid
的ItemDataBound
事件中附加到列单元格中的每个按钮上,如下面的代码所示:protected override void OnItemDataBound(DataGridItemEventArgs e) { base.OnItemDataBound(e); if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem) || (e.Item.ItemType == ListItemType.SelectedItem)) { for (int i=0; i<Columns.Count;i++) { if (Columns[i] is CmdButtonColumn) { CmdButtonColumn column = (CmdButtonColumn)Columns[i]; ((Button)e.Item.Cells[i].Controls[0]).Attributes.Add( "OnClick", column.PreStatement + "__SetCmd('" + column.Cmd + "','" + this.ID + "$" + e.Item.ItemIndex.ToString() + "');"); } } } }
ASQLDataGridCmdExecutor 类
与第一篇文章中的版本相比,我们的标准命令执行器将处理一些新命令,例如:
DG_NEW
:将新行添加到DataGrid
的顶部。DG_CANCEL
:取消当前编辑(无论是添加新行还是修改现有行)。DG_SAVE
:保存更改。DG_EDIT
:将一行设置为编辑模式。DG_DELETE
:从DataGrid
中删除一行。
实现相当直接,您可以在类的 ExecuteCmd
方法中查看详细信息。
ASQLDataGridStatBuilder 类
除了第一篇文章中已有的 BuildSelect
方法外,我们还将有三个新方法来构建 INSERT
、UPDATE
和 DELETE
语句。让我们先仔细看看 BuildInsert
方法:
public virtual string BuildInsert(ASQLDataGrid dg)
{
return "insert into " + INS_BuildIntoClause(dg) +
INS_BuildListOfColumns(dg) +
INS_BuildListOfValues(dg);
}
INS_BuildIntoClause
方法从 DataGrid
的 ID 中提取数据库表名,就像 BuildSelect
方法中的 SEL_BuildFromClause
一样。INS_BuildListOfColumns
以与 SEL_BuildListOfColumns
方法相同的方式返回列列表。INS_BuildListOfValues
通过为 DataGrid
中的每列调用 GetColumnValue
方法来构建新行(第 0 行)中每个单元格值的逗号分隔列表。如果列是 BoundColumn
,则 GetColumnValue
方法会检查当前单元格是否包含 TextBox
或仅包含文本。返回值将是 TextBox
的当前文本或单元格本身的文本。
if (dg.Columns[ColumnIndex] is BoundColumn)
{
if (dg.Items[RowIndex].Cells[ColumnIndex].HasControls())
{
control =
dg.Items[RowIndex].Cells[ColumnIndex].Controls[0];
if (control is TextBox)
{
Value = ((TextBox)control).Text;
}
}
else
{
Value = dg.Items[RowIndex].Cells[ColumnIndex].Text;
}
}
对于 TemplateColumns
,当前方法可以获取列包含 ListControl
或 CheckBox
时的单元格值。在任何其他情况下,将返回一个空字符串,这意味着 BuildInsert
方法将在语句中省略该列。事实上,如果数据库列名或其值返回为空字符串,则该列将从语句中省略。当然,您始终可以拥有自己的 Statement Builder,并且如果默认行为不满足您的需求,则可以覆盖语句的任何部分。
这里有一个重要的注意事项是,返回值是“原样”的,没有任何验证或格式化。在您的实际应用程序中,您可能需要在允许 ASQLDataGrid
类自动执行语句之前,添加自己的单元格值验证和格式化。
这是 BuildUpdate
方法的实现方式:
public virtual string BuildUpdate(ASQLDataGrid dg)
{
string sWhere = UPD_BuildWhereClause(dg);
if (sWhere.Length == 0)
{
//Prevent unintentional update of all the data
throw new Exception("The update statement " +
"requires the correct where clause to work with!");
}
return "update " + UPD_BuildTableName(dg) +
" set " + UPD_BuildSetClause(dg) +
UPD_BuildFromClause(dg) + " where "
+ sWhere;
}
要构造 UPDATE
语句的 WHERE
子句,我们需要 ASQLDataGrid
的一个新属性:ListOfPKColumns
字符串,其中包含参与数据库表主键的列索引的逗号分隔列表。通常,就像在我们的示例项目中一样,只有一个列——在我们的例子中是 EmployeeID,所以我们将 ListOfPKColumns = "0"
。UPD_BuildWhereClause
获取 ListOfPKColumns
中的所有列,获取列的数据库名称和当前值的配对,并返回 WHERE
子句,如下所示:
PKColName1 = 'CurrentValue1' and PKColName2 = 'CurrentValue2'
为防止意外更新数据库表中的所有数据,如果 UPD_BuildWhereClause
返回空字符串,BuildUpdate
将抛出异常。UPD_BuildSetClause
方法与 UPD_BuildWhereClause
的工作方式非常相似,只是它处理所有 **不** 在 ListOfPKColumns
中的列。
DELETE
语句的语法是最简单的。这是 BuildDelete
方法的样子:
public virtual string BuildDelete(ASQLDataGrid dg, int RowIndex)
{
string sWhere = DEL_BuildWhereClause(dg, RowIndex);
if (sWhere.Length == 0)
{
//Prevent unintentional delete of all the data
throw new Exception("The delete statement " +
"requires the correct where clause " +
"to work with!");
}
return "delete from " + DEL_BuildFromClause(dg) +
" where " + sWhere;
}
DEL_BuildWhereClause
与 ListOfPKColumns
属性配合使用,就像 UPD_BuildWhereClause
一样。
示例项目
我们将对第一篇文章的示例项目做一些小的修改。首先,我们将 ReportsTo
BoundColumn
更改为包含 DropDownList
的 TemplateColumn
。此 DropDownList
的内容在 DataGrid
的(实例级别)ItemDataBound
事件处理程序中填充。
private void DG_Employees_ItemDataBound(object sender,
System.Web.UI.WebControls.DataGridItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.EditItem)
{
//Populating the DropDownList with the employees' names
...
}
}
因为 EmployeeID 是数据库中的标识列——这意味着值将由数据库引擎生成,我们应该指示 Statement Builder 在 INSERT
语句中省略该列。如前所述,如果数据库列名返回为空字符串,则该列将被省略——方法如下:
public override string GetDBColumnName(TypeOfSQLStatement stat,
ASQLDataGrid dg, int ColumnIndex)
{
...
else if (stat == TypeOfSQLStatement.Insert)
{
if (ColumnIndex == 0)
{
//Skip the EmployeeID because
//it is an identity column
return "";
}
else
return base.GetDBColumnName(stat,
dg, ColumnIndex);
}
...
}
最后,我们应该为 ListOfPKColumns
属性指定正确的值。由于 Employee 数据库表的主键是 EmployeeID 列,我们将 ListOfPKColumns="0"
。
结论
我最早的自动 SQL 组件是在 1993 年用一种名为 Gupta SQL Windows 4.0 的编程语言编写的(非常感谢 Németh Miklós),从那时起,我就一直将其包含在我的类库中,包括我最近的 .NET 类库。您可能需要一些时间来掌握这个想法,但我希望您会发现它很有用,就像我和我的团队一样。
编程愉快,富有创造力!
历史
- 2005 年 8 月 8 日 - 初始版本。