22.3.2 选择数据
定义了数据连接后,就可以从可用的列表中选择一个表(或视图),把该表从项目中拖放到活动的窗体上,如图22-21所示。

图 22-21
在本例中,选择Customers表。把这个对象拖放到项目中时(可以把它拖放到窗体上,或者拖放到服务器控件面板上),就会在窗体上添加一个派生于SqlDataAdapter或 OleDbDataAdaptor的对象(如果没有使用SQL Server)。
生成的数据适配器包含SELECT、INSERT、UPDATE和DELETE命令。显然,也可以调用存储过程,而不直接使用SQL命令。向导生成的代码也可以完成这个工作。Visual Studio .NET给.cs文件添加如下代码:
private System.Data.SqlClient.SqlCommand sqlSelectCommand1;
private System.Data.SqlClient.SqlCommand sqlInsertCommand1;
private System.Data.SqlClient.SqlCommand sqlUpdateCommand1;
private System.Data.SqlClient.SqlCommand sqlDeleteCommand1;
private System.Data.SqlClient.SqlDataAdapter sqlDataAdapter1;
为每个SQL命令定义一个对象和一个SqlDataAdapter。在文件后面的InitializeComponent方法中,向导生成了创建这些命令和数据适配器的代码。
在Visual Studio .NET生成的代码中,需要解释两个地方:UpdateCommand和InsertCommand属性。下面是显示有关信息的节选版本:
//
// sqlInsertCommand1
//
this.sqlInsertCommand1.CommandText = @"INSERT INTO Customers
(CustomerID, CompanyName, ContactName,
ContactTitle, Address, City, Region,
PostalCode, Country, Phone, Fax)
VALUES(@CustomerID, @CompanyName, @ContactName, @ContactTitle,
@Address, @City, @Region, @PostalCode, @Country, @Phone, @Fax);
SELECT CustomerID, CompanyName, ContactName, ContactTitle, Address,
City, Region, PostalCode, Country, Phone, Fax
FROM Customers WHERE (CustomerID = @CustomerID)";
this.sqlInsertCommand2.Connection = this.sqlConnection1;
this.sqlInsertCommand2.Paramaters.Add(
new System.Data.SqlClient.SqlParamater("@CustomerID",
System.Data.SqlDbType.NVarChar, 5, "CustomerID"));
// Other Paramaters omitted for clarity
//
// sqlUpdateCommand1
//
this.sqlUpdateCommand2.CommandText = @"UPDATE Customers
SET CustomerID = @CustomerID, CompanyName = @CompanyName,
ContactName = @ContactName, ContactTitle = @ContactTitle,
Address = @Address, City = @City, Region = @Region,
PostalCode = @PostalCode, Country = @Country,
Phone = @Phone, Fax = @Fax
WHERE (CustomerID = @Original_CustomerID)
AND (Address = @Original_Address OR @Original_Address IS NULL
AND Address IS NULL )
AND (City = @Original_City OR @Original_City IS NULL AND City IS NULL)
AND (CompanyName = @Original_CompanyName)
AND (ContactName = @Original_ContactName OR @Original_ContactName IS NULL
AND ContactName IS NULL )
AND (ContactTitle = @Original_ContactTitle OR @Original_ContactTitle IS NULL
AND ContactTitle IS NULL )
AND (Country = @Original_Country OR @Original_Country IS NULL
AND Country IS NULL )
AND (Fax = @Original_Fax OR @Original_Fax IS NULL AND Fax IS NULL)
AND (Phone = @Original_Phone OR @Original_Phone IS NULL AND Phone IS NULL)
AND (PostalCode = @Original_PostalCode OR @Original_PostalCode IS NULL
AND PostalCode IS NULL )
AND (Region = @Original_Region OR @Original_Region IS NULL
AND Region IS NULL );
SELECT CustomerID, CompanyName, ContactName, ContactTitle,
Address, City, Region, PostalCode, Country, Phone, Fax
FROM Customers
WHERE (CustomerID = @ CustomerID)";
this.sqlUpdateCommand2.Connection = this.sqlConnection1;
this.sqlUpdateCommand2.Paramaters.Add(
new System.Data.SqlClient.SqlParamater("@CustomerID",
System.Data.SqlDbType.NVarChar, 5, "CustomerID"));
// Other Paramaters omitted for clarity
这些命令中的主要部分是已经生成的SQL。对于INSERT和UPDATE命令,有两条SQL语句—— 一条语句用于插入或更新数据,另一条语句用于重新从数据库中选择数据行。
这些看起来多余的子句是使客户机上的数据与服务器上数据重新保持同步的一种方式。默认情况下,在插入时这些语句会应用到列上,否则数据库的触发器就会更新已插入/更新记录中的列,数据的重新同步有一些优点。用于重新选择数据的@CustomerID参数与主键码的INSERT/UPDATE语句中的值相等—— 名称是由向导自动生成的。
对于包含IDENTITY列的表,生成的SQL会在插入语句后使用@@IDENTITY值,如第21章所述,利用@@IDENTITY生成主键码,会产生一些恼人的错误,因此要手工修改SQL的这个地方。同样,如果没有计算好列,在更新了一些数据后,重新选择源表中的所有列就会浪费时间。
向导生成的代码可以工作,但有时它并不是最佳的。对于产品系统,所有生成的SQL语句都应用存储过程的调用来替换。如果INSERT或UPDATE子句不需要重新同步数据,删除多余的SQL子句可以加速应用程序的运行。





