357
Console.WriteLinerowDescription, DataRowVersion.Current Console.WriteLinerowDescription, DataRowVersion.Default
Console.WriteLinerowDescription
Calling the DataSet objects AcceptChanges method commits outstanding changes. Calling the DataSet objects RejectChanges method rolls records back to their original versions.
The code shown in this section affects only the DataSet object, not the data source. To propagate these changes, additions, and
deletions back to the data source, use the Update method of the SqlDataAdapter class, as described in
Sect ion 8.5.7 .
If there are relations defined between the DataTables in the DataSet, it may be necessary to call the DataRow objects
BeginEdit method before making changes. For more information, see
Sect ion 8.6 later in this chapter.
8.5.7 Writing Updates Back to the Data Source
Because DataSets are always disconnected from their data sources, making changes in a DataSet never has any effect on the data source. To propagate changes, additions, and deletions back to a
data source, call the SqlDataAdapter classs Update method, passing the DataSet and the name of the table that is to be updated. For example, the following call to Update writes changes from the
DataTable named Categories back to the SQL Server table of the same name:
da.Updateds, Categories Before using the Update method, however, you should understand how an SqlDataAdapter object
performs updates. To change, add, or delete records, an SqlDataAdapter object must send SQL UPDATE
, INSERT
, or DELETE
statements, respectively, to SQL Server. The forms of these statements either can be inferred from the
SELECT statement that was provided to the SqlDataAdapter object or
can be explicitly provided to the SqlDataAdapter object. Ex am ple 8- 2
shows an example of allowing an SqlDataAdapter object to infer the SQL UPDATE
, INSERT
, and DELETE
statements required for applying updates to a database.
Example 8-2. Allowing an SqlDataAdapter object to infer SQL UPDATE, INSERT, and DELETE statements from a SELECT statement
Open a database connection. Dim strConnection As String = _
Data Source=localhost;Initial Catalog=Northwind; _ Integrated Security=True
Dim cn As SqlConnection = New SqlConnectionstrConnection cn.Open
Create a data adapter object and set its SELECT command. Dim strSelect As String = _
SELECT FROM Categories Dim da As SqlDataAdapter = New SqlDataAdapterstrSelect, cn
Set the data adapter objects UPDATE, INSERT, and DELETE commands. Use the SqlCommandBuilder classs ability to auto-
generate these commands from the SELECT command.
358
Dim autogen As New SqlCommandBuilderda Load a data set.
Dim ds As DataSet = New DataSet da.Fillds, Categories
Get a reference to the Categories DataTable. Dim dt As DataTable = ds.TablesCategories
Modify one of the records. Dim row As DataRow = dt.SelectCategoryName = Dairy Products0
rowDescription = Milk and stuff Add a record.
row = dt.NewRow rowCategoryName = Software
rowDescription = Fine code and binaries dt.Rows.Addrow
Delete a record. row = dt.SelectCategoryName = MyCategory0
row.Delete Update the database.
da.Updateds, Categories Close the database connection.
cn.Close
Note the following in Ex am ple 8- 2
: 1. A SqlDataAdapter object is constructed with an argument of
SELECT FROM Categories
. This initializes the value of the SqlDataAdapter objects SelectCommand property.
2. A SqlCommandBuilder object is constructed with the SqlDataAdapter object passed as an argument to its constructor. This step hooks the SqlDataAdapter object to the
SqlCommandBuilder object so that later, when the SqlDataAdapter objects Update method is called, the SqlDataAdapter object can obtain SQL
UPDATE ,
INSERT , and
DELETE commands
from the SqlCommandBuilder object. 3. The SqlDataAdapter object is used to fill a DataSet object. This results in the DataSet object
containing a DataTable object, named Categories, that contains all the rows from the Northwind databases Categories table.
4. One record each in the table is modified, added, or deleted. 5. The SqlDataAdapter objects Update method is called to propagate the changes back to the
database. Step 5 forces the SqlCommandBuilder object to generate SQL statements for performing the database
update, insert, and delete operations.When the Update method is called, the SqlDataAdapter object notes that no values have been set for its UpdateCommand, InsertCommand, and DeleteCommand
properties, and therefore queries the SqlCommandBuilder object for these commands. If any of these properties had been set on the SqlDataAdapter object, those values would have been used instead.
The SqlCommandBuildObject can be examined to see what commands were created. To see the commands that are generated in
Ex am ple 8- 2 , add the following lines anywhere after the declaration
and assignment of the autogen variable: Console.WriteLineUpdateCommand: autogen.GetUpdateCommand.CommandText
Console.WriteLineInsertCommand: autogen.GetInsertCommand.CommandText Console.WriteLineDeleteCommand: autogen.GetDeleteCommand.CommandText
359
The auto-generated UPDATE
command contains the following text note that line breaks have been added for clarity in the book:
UPDATE Categories SET CategoryName = p1 , Description = p2 , Picture = p3
WHERE CategoryID = p4
AND CategoryName IS NULL AND p5 IS NULL OR CategoryName = p6
Similarly, the INSERT
command is: INSERT INTO Categories CategoryName , Description , Picture
VALUES p1 , p2 , p3 And the
DELETE command is:
DELETE FROM Categories WHERE
CategoryID = p1 AND
CategoryName IS NULL AND p2 IS NULL OR CategoryName = p3
Note the use of formal parameters p0
, p1
, etc. in each of these statements. For each row that is to be changed, added, or deleted, the parameters are replaced with values from the row, and the
resulting SQL statement is issued to the database. The choice of which value from the row to use for which parameter is controlled by the SqlCommand objects Parameters property. This property
contains an SqlParameterCollection object that in turn contains one SqlParameter object for each formal parameter. The SqlParameter objects ParameterName property matches the name of the
formal parameter including the
, the SourceColumn property contains the name of the column from which the value is to come, and the SourceVersion property specifies the version of the value
that is to be used. Row versions were discussed in Sect ion 8.5.6
. If desired, a DataSet objects UpdateCommand, InsertCommand, and DeleteCommand properties can
be set directly. Ex am ple 8- 3
sets the value of UpdateCommand and then performs an update using this command.
Example 8-3. Setting a DataSet objects UpdateCommand property
Open a database connection. Dim strConnection As String = _
Data Source=localhost;Initial Catalog=Northwind; _ Integrated Security=True
Dim cn As SqlConnection = New SqlConnectionstrConnection cn.Open
Set up a data adapter object. Dim da As SqlDataAdapter = New SqlDataAdapterSELECT FROM Categories,
cn Create an UPDATE command.
This is the command text. Note the parameter names: Description and CategoryID.
Dim strUpdateCommand As String = _ UPDATE Categories _
SET Description = Description _ WHERE CategoryID = CategoryID
360
Create a SqlCommand object and assign it to the UpdateCommand property. da.UpdateCommand = New SqlCommandstrUpdateCommand, cn
Set up parameters in the SqlCommand object. Dim param As SqlParameter
CategoryID param = da.UpdateCommand.Parameters.Add _
New SqlParameterCategoryID, SqlDbType.Int param.SourceColumn = CategoryID
param.SourceVersion = DataRowVersion.Original Description
param = da.UpdateCommand.Parameters.Add _ New SqlParameterDescription, SqlDbType.NChar, 16
param.SourceColumn = Description param.SourceVersion = DataRowVersion.Current
Load a data set. Dim ds As DataSet = New DataSet
da.Fillds, Categories Get the table.
Dim dt As DataTable = ds.TablesCategories Get a row.
Dim row As DataRow = dt.SelectCategoryName = Dairy Products0 Change the value in the Description column.
rowDescription = Milk and stuff Perform the update.
da.Updateds, Categories Close the database connection.
cn.Close
8.6 Relations Between DataTables in a DataSet
The DataSet class provides a mechanism for specifying relations between tables in a DataSet. The DataSet classs Relations property contains a RelationsCollection object, which maintains a collection
of DataRelation objects. Each DataRelation object represents a parentchild relationship between two tables in the DataSet. For example, there is conceptually a parentchild relationship between a
Customers table and an
Orders table, because each order must belong to some customer.
Modeling this relationship in the DataSet has these benefits: •
The DataSet can enforce relational integrity. •
The DataSet can propagate key updates and row deletions. •
Data-bound controls can provide a visual representation of the relation. Ex am ple 8- 4
loads a Customers
table and an Orders
table from the Northwind database and then creates a relation between them. The statement that actually creates the relation is shown in bold.
Example 8-4. Creating a DataRelation between DataTables in a DataSet
Open a database connection. Dim strConnection As String = _
Data Source=localhost;Initial Catalog=Northwind; _ Integrated Security=True