Bob Swart
Bob Swart Training & Consultancy
2004 年 1 月 本文展示了如何使用 IBM DB2 UDB 表、C#Builder 和 BDP for .NET 构建一个应用程序,然后将其作为一个 ASP.NET Web 表单(带有一个强大的 asp:DataGrid 控件)来部署,以便用户可以通过 Web 浏览器与 DB2 UDB 表打交道。
简介
在我的 第一篇 有关与 Borland® C#Builder TM一起使用 IBM® DB2® Universal Database TM (UDB) 的文章中,我展示了如何使用 Borland Data Providers (BDP) for .NET 来构建一个到 DB2 UDB v8.1 的连接以及如何使用 DB2 SAMPLE 表。在 第二篇文章 中,我更详细地分析了一些单个的 Borland Data Provider 类,尤其是设计时(design-time)编辑器,并且还部署了一个 WinForms 应用程序。
在本文中,我将展示如何使用 DB2 UDB 表来构建一个类似的应用程序,不过这次我将把它部署为一个 ASP.NET Web 表单(带有一个强大的 asp:DataGrid 控件),这样用户就可以通过 Web 浏览器来与 DB2 UDB 表打交道。
构建 ASP.NET Web 表单
首先,我们使用 C#Builder 创建一个 ASP.NET Web Form 应用程序,然后添加到 DB2 UDB SAMPLE 表的连接,最后使用 asp:DataGrid 控件配置用户界面。
与前一篇文章一样,我将在 Microsoft® .NET Framework 1.1 上结合使用 IBM DB2 UDB v8.1 和 C#Builder Enterprise。要创建 ASP.NET Web 表单,需要一个 Web 服务器,比如说 Microsoft 的 Internet Information Server (IIS)。如果没有安装 IIS,那么也可以使用免费的 ASP.NET Cassini Web 服务器——一个样本 Web 服务器,您可以在 C#Builder 的 BDS\\1.0\\Examples\\C#\\Cassini 目录中找到它的完整源代码以及安装指令。
要构建这个应用程序,先启动 C#Builder,然后选择 File > New,键入 ASP.NET Web Application 。您将看到 New ASP.NET Application 对话框,在这里可以指定项目的名称(参见图 1)。这个名称将用于创建一个新的虚拟目录(virtual directory),项目文件都将存放在这个目录中。虽然最好使用与 ASP.NET Web Form 将被部署到的虚拟目录相同的名称(参见 部署应用程序),但是并不一定要这么做。我指定了 DB2UDB 作为名称,以表明这是一个要连接和使用 DB2 UDB 表的 ASP.NET Web 表单。
图 1. 选择 IIS 或 Cassini 作为 Web 服务器
注意,从图 1 您可以指定想要的 Web 服务器,用以部署这个项目(我选择使用 IIS,但是只要愿意,您也可以选择 Cassini)。
点击 OK 按钮后,便在新虚拟目录中创建了一个新的 C#Builder 项目。不过,这次不是一个 WinForm,而是一个 WebForm,您可以在其中放置一些特殊的 Web 组件。不过,首先还应该建立到 DB2 UDB SAMPLE 表的连接。
连接到 DB2 UDB
与上次一样,可以通过多种方式建立到 DB2 UDB SAMPLE 表的连接。您可以使用 Data Explorer 将一个表拖放到 Web Forms 上。或者也可以以一种显式的方式来做这件事(这样您可以对这种“魔术”有更大的控制力),在这里我们正是这么做的。那么,首先将一个 BdpConnection 组件拖到 WebForm 上。注意,它将显示在 designer 的非可视部分,WebForm 的下方。
选择 BdpConnection 组件,从 Object Inspector 使用 Connections Editor 动词,或者右键点击 BdpConnection 组件,以启动 Connections Editor。
图 2. Borland Data Provider:Connections Editor
在默认情况下,只会显示 4 种连接,分别针对的是:InterBase、MS SQL Server、Oracle 和 DB2。这 4 种连接都是“样本”连接,我自己从来没有使用过,不过我认为在这里它们可以作为有用的例子。如果您以前没有连接过 DB2 UDB,那么点击 Add 以创建一个特定的到 DB2 SAMPLE 数据库表的 DB2 连接。
图 3. 添加新的连接
点击 OK,回到 Connections Editor,指定 SAMPLE 作为数据库名,然后键入 DB2 用户的正确的密码和用户名。可以使用 Test 按钮查看连接的属性是否设置得当,以保证能够与 DB2 UDB SAMPLE 表进行通信。
配置 DB2 数据集
接下来,拖放一个 BdpDataAdapter 组件。您可以使用动词 Configurate Data Adapter 或 Generate Typed Dataset,或者右键点击 BdpDataAdapter 组件并进行同样的选择。这次不需要生成一个类型化数据集(typed dataset),因此可以选择 Configurate Data Adapter。
在 Data Adapter Configuration 对话框中,去掉 Update、 Insert 和 Delete选项前面的对勾,并选中 Optimize 选项。点击 Generate SQL 以产生 SQL 语句(参见图 4)。或者,您也可以自己在这里输入 SELECT * from ADMINISTRATOR.EMPLOYEE 语句。
图 4. Data Adapter Configuration 向导——Command
点击 DataSet标签,选择 New DataSet (参见图 5)。这将自动地创建一个新的 DataSet (称为 dataSet1)并且将它连接到 SQL 命令的输出。
图 5. Data Adapter Configuration 向导——DataSet
现在,点击 Preview Data 以进行预览。注意,要再次查看数据,必须点击 Refresh 按钮。还应注意的是,您可以限制这里数据显示的行数。默认情况下是显示前 100 行,但是对于 ASP.NET Web 表单,您可能需要进一步加以限制,例如要求显示前 10 行记录。因此,将 Rows to fetch 的值设置为 10,然后点击 Refresh。
图 6. Data Adapter Configuration 向导——preview data
在关闭 Data Adapter Configuration 向导的时候您可能会注意到,我们在这里指定的 10 这个值并没有与 MaxRecords 属性的值(仍然是 100)关联起来。这意味着在显示记录时最多仍可以显示 100 行,而不是 10 行,不过在本文的后面(讲到分页的时候)我们将解决这个问题。
注意,在 WebForm 中 designer 的非可视(non-visual)区域,将看不到 dataSet1 组件已被添加的可视化“证据”。您需要显式地在 designer 的这块区域中点击右键并选择 Line up Icons 选项,这样才能刷新屏幕并显示 dataSet1(这是为了确认没有丢失什么)。
到目前为止,所有事项都相对比较容易,对于连接到 DB2 的任务,您可以执行与上次几乎一样的步骤。不过,从现在开始,与 WinForms 方法相比事情将会有所不同。
控制 Web
现在,是添加 ASP.NET Web 控件的时候了,这些控件都属于 Web Controls 种类(注意,您也可以添加属于 HTML Elements 种类的控件,不过这些控件不够强大)。为了仿效上一次的应用程序,需要使用一个 asp:DataGrid 控件,所以这里将一个这样的控件拖到 WebForm 上。一开始,将显示 3 列、5 行(不包括头部在内),所有值暂时都是“abc”。但是您可以使用 DataSource 属性将 asp:DataGrid 绑定到 dataSet1 组件。除了将 DataSource 指向 dataSet1 外,还需要将 DataMember 属性指向 Table1。
图 7. C#Builder 设计时概览
尽管这将显示更多的列(对于每个字段,其标题也要显示在列标题中——从数据集的元数据获得),在设计时将不会显示实际的数据。而且,这里只能看到 5 条记录,而不是在 Data Adapter Configuration 向导中指定的 10 条。
为了快速地对 asp:DataGrid 进行配置,您可以点击 Auto Format 动词(在图 7 的左下位置),这将弹出如图 8 所示的 Auto Format 对话框,从中可以选择一个特殊的预定义的模式(比如 Professional 1,我选择的就是这个模式)。
图 8. DataGrid Auto Format
在可以编译和运行应用程序以查看实际的输出之前,必须首先确保将数据绑定到了 asp:DataGrid 。数据绑定需要在运行时进行,最好是在 ASP.NET Page_Load 事件处理程序中进行。双击 Web 表单,您将进入代码编辑器,以编辑 Page_Load 事件。写入如下代码:
private void Page_Load(object sender, System.EventArgs e)
{
// Put user code to initialize the page here
if (!IsPostBack)
dataGrid1.DataBind();
}
|
这将确保 DataGrid 的 DataBind 方法只能在第一次(即进入 ASP.NET Web Form 的时候)被调用。在所有其他的时候(例如返回信息的时候), asp:DataGrid 已经被绑定到数据,因此不需要再次调用 DataBind 。过一会我还会谈到这一点。
运行和调试 Web 表单
现在,您可以保存该项目,编译并准备运行它。在 C:\\Inetpub\\wwwroot 目录下将包含一个名为 DB2UDB 的目录,这个目录中存放着该项目的文件。DB2UDB 目录有一个 Bin 子目录,其中有 DB2UDB.dll 文件。通过浏览器,您可以使用 http://localhost/DB2UDB/WebForm1.aspx (主表单的名称)这个 URL 来启动该项目。不过,我认为在运行期间调试代码更可行,所以还是按 F9 来运行这个 ASP.NET 应用程序,这样一来 IDE 就处在“调试模式”下,再启动浏览器,进入起始页。
在这两种情况下,结果都是一样的,如图 9 所示。
图 9. 带有 DataGrid 的 ASP.NET Web Form(显示多条记录)
注意,您从 DB2 UDB SAMPLE 数据库的 EMPLOYEE 表中得到的是所有的记录(或者至少是前 100 条记录——由 MaxRecords 指定)。这看起来不是很“专业”,我是这么认为的,因为用户必须拖动滚动条来查看所有记录(而且,当处在第 20 条记录或者更靠后的记录时,就看不到列标题了)。而且,如果将多条记录从服务器发送到客户机,那么您将遇到性能问题和带宽瓶颈。在实际情况中这些问题经常会出现,由于我们只创建了一个简单的、不带限制性的 WHERE 子句的 SELECT 语句,因此这些问题更容易发生。
对 DB2 数据进行排序和分页
为了帮助解决这个问题,可能需要更细致地配置 asp:DataGrid 选项。关闭浏览器(这将使您回到 C#Builder IDE),选择 asp:DataGrid ,这次点击 Property Builder(位于屏幕左下方)以弹出 DataGrid Properties 对话框。
第一页用于确认 DataSource 和 DataMember属性以及 Data key field等的值。还应注意 Allow sorting 选项,我已经选中了这个选项。
图 10. DataGrid Properties——General
为了允许排序,您还必须再做两件事:指定排序表达式,以及为 SortCommand 编写一些代码。
可以在 DataGrid Properties 向导的 Columns 页上指定排序表达式(参见图 11)。
图 11. DataGrid Properties——Columns
对于每一列,您可以设置排序表达式(通常等于字段名)。这样做将使列标题变为一个超链接,如果点击这个超链接,就会触发 SortCommand 事件处理程序的执行,并且以 Sort Expression 的特定值作为参数。既然这是实际的字段名,那么为了对 asp:DataGrid 进行排序,只需再次对 DB2 UDB 执行 SQL 查询,不过这次要添加一个 ORDER BY 子句,后面跟上作为排序表达式传递进来的那个字段名。
asp:DataGrid 的针对 SortCommand 事件处理程序的 C# 源代码如下所示:
private void dataGrid1_SortCommand(object source,
System.Web.UI.WebControls.DataGridPageChangedEventArgs e)
{
Session["OrderBy"] = e.SortExpression; // Order By FieldName
bdpDataAdapter1.Active = false;
bdpSelectCommand1.CommandText = "SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, " +
" WORKDEPT, PHONENO, HIREDATE, JOB, EDLEVEL, SEX, BIRTHDATE, SALARY, " +
"BONUS, COMM FROM ADMINISTRATOR.EMPLOYEE";
if ((Session["OrderBy"] != null) && ((string)Session["OrderBy"] != ""))
bdpSelectCommand1.CommandText += " ORDER BY " + (string)Session["OrderBy"];
bdpDataAdapter1.Active = true;
dataGrid1.DataBind();
label1.Text = this.bdpSelectCommand1.CommandText +
" (Page " + (dataGrid1.CurrentPageIndex+1).ToString() + ")";
}
|
注意,我将 SortExpression 保存在 ASP.NET Session 变量中,所以每当回到这个页面并且必须再次执行这个查询时(例如当您想跳到另一个页面的时候),可以确保使用的是一样的排序。
说到进入下一个页面:您可以指定 asp:DataGrid 在一个特定页面上可以显示的最大记录数(还记得 图 9 吗,它在表格中显示了所有的记录——当然,对于 DB2 UDB SAMPLE 数据库中的 EMPLOYEE 表来说这算不了什么,但是,在实际中如果使用一个更大的表的话,就会有潜在的问题)。我们已经将页面大小指定为 10 行。这意味着您将得到多个页面——每一页面10行记录——并且当用户想要从一个页面导航到另一个页面时(使用 Next 和 Previous 按钮,如图 12 中所指定的,或者也可以使用页面号),应用程序将不得不对相应的事件作出响应。
图 12. DataGrid Properties——Paging
当用户点击某个导航按钮时,就触发了 asp:DataGrid 的 PageIndexChanged 事件。您可以使用 CurrentPageIndex 属性来指定 asp:DataGrid 必须以某个特定页面作为起始页。不幸的是,这个属性必须在数据被绑定到 asp:DataGrid 之前设置好,否则表格中就已经含有了数据。所以,您必须再次绑定数据,也就是说,必须再让 BdpDataAdapter 组件处于不激活状态,然后再次将合适的值赋给 CommandText 属性(在当前选中的列上对表进行排序),最后在 asp:DataGrid 中绑定数据,如以下源代码所示:
private void dataGrid1_PageIndexChanged(object source,
System.Web.UI.WebControls.DataGridPageChangedEventArgs e)
{
dataGrid1.CurrentPageIndex = e.NewPageIndex; // Go to Page index
bdpDataAdapter1.Active = false;
bdpSelectCommand1.CommandText = "SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, " +
" WORKDEPT, PHONENO, HIREDATE, JOB, EDLEVEL, SEX, BIRTHDATE, SALARY, " +
"BONUS, COMM FROM ADMINISTRATOR.EMPLOYEE";
if ((Session["OrderBy"] != null) && ((string)Session["OrderBy"] != ""))
bdpSelectCommand1.CommandText += " ORDER BY " + (string)Session["OrderBy"];
bdpDataAdapter1.Active = true;
dataGrid1.DataBind();
label1.Text = this.bdpSelectCommand1.CommandText +
" (Page " + (dataGrid1.CurrentPageIndex+1).ToString() + ")";
}
|
现在可以再次关闭 DataGrid Property Builder 对话框了。在设计时, asp:DataGrid 将在列标题中显示超链接,在 asp:DataGrid 的页脚处显示 Next 和 Previous 按钮(参见图 13)。
图 13. C#Builder HTML 设计时概览
您可能还想做更多的事情:在第一次创建 ASP.NET Web Form (在 Page_Load 事件处理程序中)的时候,您可能想清除 OrderBy Session 变量,并设置一个值为 asp:label 控件(顺便说一下,我这么做主要是为了调试,但是这对于显示被执行的 SQL 语句以及当前看到的页面号也是很有用的)。
private void Page_Load(object sender, System.EventArgs e)
{
// Put user code to initialize the page here
if (!IsPostBack)
{
Session["OrderBy"] = "";
dataGrid1.DataBind();
label1.Text = this.bdpSelectCommand1.CommandText +
" (Page " + (dataGrid1.CurrentPageIndex+1).ToString() + ")";
}
}
|
从 C#Builder IDE 中编译和运行这个 ASP.NET 应用程序的结果在图 14 中可以看到。注意,一开始执行的 SQL 语句(等同于 select * from employee )没有 order by 子句,并且是从第一页开始的。
图 14. 最后的 ASP.NET 输出(起始页)
我们可以点击 > 按钮来转到下一页,如图 15 所示。
图 15. 最后的 ASP.NET 输出(第 2 页)
现在可以点击 FIRSTNME列,以便按照这个字段对 asp:DataGrid 进行排序,如图 16 所示。注意,现在您停留在第 2 页,但是这次 SQL 查询带有一个针对 FIRSTNME 字段的 order by 子句。
图 16. 最后的 ASP.NET 输出(按 firstnme 排序)
可选地,您可能要在 SortCommand 事件处理程序中重设 asp:DataGrid 的 CurrentPageIndex 属性,以便当您希望对表格中的数据重新排序时总可以回到第一页。要做到这一点,可以将下面这行代码作为第一行添加到 SortCommand 事件处理程序中:
dataGrid1.CurrentPageIndex = 0; // first page (start to count at 0)
|
部署应用程序
到了要部署应用程序的时候,您很可能想将它部署在一个这样的 Web 服务器上:在其中可以访问 DB2 UDB (因此需要安装 DB2 客户机),而且通常不会安装有 C#Builder。这意味着必须将应用程序的一些文件移到最终的 Web 服务器上。对于当前的例子来说,这意味着您需要部署 web.config、global.asax (没被修改过)以及 WebForm1.aspx (包含用于 ASP.NET Web 表单的 HTML 文件)。当然,您还需要部署 Bin 子目录中的 DB2UDB.dll 。这个文件包含了 ASP.NET Web Form 的编译好了的 Code Behind 部分。
除了这些特定于项目的(例子)文件之外,您还需要部署一些 Borland Data Provider 文件。从 bdpdb2.dll 文件开始,这个文件必须放在这个路径中,或者像早期常用的做法一样,将它放在同一个 Bin 目录中,也就是用于部署 DB2UDB.dll 文件的那个目录。通过这种方法,ASP.NET Web Form 将自动找到 dbpdb2.dll 。
这三个 BDP 组件( Borland.Data.Provider.dll 、 Borland.Data.Common.dll 和 Borland.Data.Db2.dll )可以与 Code Behind 文件放在同一个目录中,但是在这里最好还是通过使用 gacutil 将它们部署在 Global Assembly Cache 中。在后面的例子中,它们将被放在 .NET Web 服务器上以供共享,其他 (ASP).NET 应用程序也可以使用它们。
结束语
在本文中,我展示了 DB2 UDB 是用于构建 ASP.NET Web 表单的强大的 DBMS,在这样的 ASP.NET Web 表单中,可以通过 Borland Data Providers for .NET 访问 DB2 中的数据。使用 Borland Data Providers 连接到 DB2 UDB 的方式是一致的,不管您要构建的是 GUI WinForms (如 上一篇文章 所讲的)还是 ASP.NET Web 表单(也就是这次所讲的)。
Borland RAD Tools 和 DB2 UDB 可以在 .NET、本地 Win32 以及 Linux 上进行连接,通过两者之间的灵活的连接,您可以构建 GUI 应用程序以及 Web 应用程序,这些应用程序可以操作 DB2 UDB 表中的数据。 |