Writing Updates Back to the Data Source

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