Using the Data Form Wizard to Build a Data-Bound Form

Using the New Data-Bound Form

Figure 2-13 shows the data-bound form that the Data Form Wizard created.

Figure 2-13

Your new data-bound form

If you build and run the project right now, you won't see the new data-bound form. Unless you've changed the properties for the project, the form that you'll see when you run the project is the form that was initially included with the project. To change the setting so the project starts with the new form, choose Properties from the Project menu in Visual Studio .NET or right-click on the project in Solution Explorer and choose Properties from the shortcut menu. You'll see the project's Property Pages dialog box. Change the project's Startup Object property to the new data-bound form, DataForm1 as shown in Figure 2-14. Click OK to save your changes.

Figure 2-14

The Property Pages dialog box for the Chapter2 project

Showing Data in Your New Data-Bound Form

To run the project and see your new data-bound form, press F5, click the Debug menu and then click Start, or click the Start button on the toolbar. You'll see that the form has labels and text boxes for each field in the Customers table as well as a data-bound grid to display the contents of the Orders table. However, the form does not show any data. All the controls are empty. The form has created a DataSet object with the tables and relationship you defined in the pages of the Data Form Wizard, but that DataSet does not yet contain data. Click the Load button in the upper-left corner of the form to see the data in your controls, as shown in Figure 2-15.

Figure 2-15

Viewing the data on the new data-bound form

A Behind-the-Scenes Look at the Wizard-Generated Code

To look at the code that your project runs when you click the Load button, close the form and return to the Visual Studio .NET development environment. Double-click the Load button, and you'll see that the code in the button's Click event calls the LoadDataSet procedure. Scroll down to the definition of this procedure and you'll see that it calls another procedure, FillDataSet. If you examine the code in this procedure, you'll find that it calls the Fill method on two OleDbDataAdapter objects, as shown in Figure 2-16.

Figure 2-16

Wizard-generated code for filling your DataSet

Calling the Fill method of the OleDbDataAdapter object executes the query stored in the SelectCommand property in the DataAdapter and stores the results in the DataSet or DataTable objects specified. The Data Form Wizard created these DataAdapter objects to fetch the contents of each table that you chose to display. The SelectCommand for each DataAdapter contains a query in the following format:

SELECT Field1, Field2, ... , FieldN FROM MyTable

Most of the buttons on the form are self-explanatory—for example, clicking the Add button adds a new customer row and clicking the Delete button deletes the current customer row. The buttons with the arrows are navigation controls that take you to the first, last, previous, and next records.

Cascading Changes with the DataRelation Object

Click the right arrow button to move to the next customer. The text boxes on the data-bound form will display information about the next customer. Because of the DataRelation you built, the grid will show just the orders for this particular customer. This relation has other features that you can use on the form.

Using the navigation buttons, move to the first customer that has child orders. Unless you've modified the contents of the tables in the sample database, the first customer, whose CustomerID setting is ALFKI, will have several orders. Change the value in the text box for the CustomerID field to Chap2. Don't worry, this won't affect the contents of the database. Next, move to the next record and then back to this record. Look at the contents of the grid. The CustomerID field for all the orders will be set to Chap2, the value you just entered. The DataRelation object we built instructed the DataSet object to cascade the change to the CustomerID column in the customer row to all the related order rows. If you were to delete the current customer from the DataSet, the DataSet would delete all the related orders as well.

Submitting Changes to Your Database

I mentioned earlier that the change to the data in the DataSet object would not affect the contents of the database. To verify this claim, close the form and rerun the project. Load the data, and then use the navigation buttons to move to the customer that you previously modified. You'll see that the CustomerID field is still set to its original value rather than to Chap3. As I mentioned in Chapter 1, the data in the DataSet object is disconnected from the database. Changes you make to the DataSet object do not directly affect the data in your database. ADO.NET does provide features that allow you to submit changes to your database, but how do you use them? In order to submit the changes back to the database, you have to use some additional functionality from the ADO.NET DataAdapter class. We'll explore that next.

Let's make another change to a customer. Move to the first customer by clicking on the double left arrow button. Add X to the end of the company name. Click the right arrow button to move to the next row. Then click the left arrow button to move back to the modified row. You'll see that the change is still stored in the DataSet object. If you were to close the form and rerun the project, you'd lose this modification.

To submit the name change, click the Update button. You might see the mouse cursor momentarily change from an arrow to an hourglass and back while the form runs the code to send the change to your database. After the cursor returns to its normal arrow, close the form and rerun the project. When you click on the Load button, you'll see the modified company name.

What code did the Update button use to submit the change to the database? To see it, close the form and return to the Visual Studio .NET development environment. Double-click the Update button to see the code contained in its Click event. The wizard-generated code creates two procedures to update your database—UpdateDataSet and UpdateDataSource. The Update button's click event calls the UpdateDataSet procedure, which, in turn, calls UpdateDataSource. Look at the definition for these procedures of the form, and you'll see the code shown in Figures 2-17 and 2-18.

Figure 2-17

The UpdateDataSet procedure generated by the Data Form Wizard

Figure 2-18

The UpdateDataSource procedure generated by the Data Form Wizard

This might look like complex code, but it's really very straightforward. For now, we'll focus on the general process and look at a couple lines of code at a time. In Chapter 10 and Chapter 11, we'll take a closer look at the process of sending updates to your database. Remember that the wizard generated this code in order to handle whatever changes you make to the data on the form. This code handles modified rows, newly created rows, and deleted rows in each table. The three methods that the wizard uses to control the update process are GetChanges, Update, and Merge.

Calling the DataAdapter Object's Update Method

Rather than discuss these methods in the order in which they appear in the code, I'd like to focus first on the Update method—the most critical part of the process.

In Chapter 1, you learned that the DataAdapter object acts as a bridge between the DataSet object and the database. The DataAdapter object's Update method submits changes stored in the DataSet to the database. Each DataAdapter object corresponds to one of the DataTable objects in our DataSet. In order to submit changes stored in both DataTable objects, you have to call the Update method on both DataAdapter objects.

When you call the Update method on a DataAdapter object, you must specify what data you want to submit to the database. The DataAdapter object is flexible and can accept a number of different structures in its Update method. The code generated by the Data Form Wizard uses a DataSet object, but you can also submit a DataTable object or an array of DataRow objects to the Update method.

The DataAdapter object examines the contents of the data structure to determine which rows it can handle. For example, the DataAdapter that the Data Form Wizard built based on the Customers table will look only at the DataTable that corresponds to the Customers table. The DataAdapter object knows which table to examine because of its TableMappings collection, which I described briefly in Chapter 1.

When the DataAdapter object detects a modified row, it determines the type of change—insert, update, or delete—and submits it to the database based on this type. If the row has been modified, the DataAdapter object executes the DataCommand stored in its UpdateCommand property, using the current contents of the row. Similarly, the DataAdapter object uses its InsertCommand to submit new rows and its DeleteCommand to delete rows.

Isolating Modified Rows

The code in the form's UpdateRowSource function calls the GetChanges method on the DataSet. The GetChanges method generates a new DataSet object named objDataSetChanges that contains only modified rows. The GetChanges method accepts an optional parameter that you can use to indicate whether you want all changes or just a specific type of change—inserts, updates, or deletes.

There's actually no need for the Data Form Wizard to use the GetChanges method to create a new DataSet object that contains only modified rows. If you call a DataAdapter object's Update method and the DataSet you supply as a parameter contains unmodified rows, those rows are simply ignored. So when would you use GetChanges?

The Data Form Wizard generates two-tier applications. The client application communicates directly with your database. If you build a multi-tiered application that uses Web services or COM+ components that run on a middle-tier server, you'll want to limit the amount of data that you pass back and forth between machines. The less data you have to pass across the wire, the faster your application will run.

If the client application has a DataSet that contains modified rows to submit to the database in such a multi-tiered application, the client sends data to the middle. There's no need to send unmodified rows back to the middle tier. Intelligent use of the GetChanges method can dramatically improve the performance of multi-tiered ADO.NET applications.

The Data Form Wizard builds two-tier applications, but the code that it generates is appropriate for multi-tiered applications.

Reintegrating Changes

When the DataAdapter object examines a modified row and successfully submits the pending change to the database, it marks the row as no longer containing a pending change. This way, the DataAdapter object doesn't send the same change to the database over and over again on subsequent calls to its Update method.

Earlier we discussed the DataSet class's GetChanges method. The code uses the DataSet object returned by the GetChanges method in the call to the DataAdapter object's Update method.

When the updates succeed, the DataAdapter objects mark the appropriate rows in the objDataSetChanges as having successfully updated the database. But the objDataSetChanges is separate from the main DataSet for the form. Somehow, we need to merge the changes that the DataAdapter objects made to the objDataSetChanges back into our main DataSet.

The DataSet class has a Merge method that you can use to merge data from two DataSet objects. If the rows in the DataSet objects represent different rows, ADO.NET simply places all the rows into the DataSet whose Merge method you called. In this case, the rows in the objDataSetChanges reference the same data in our main DataSet. We want the rows in the objDataSetChanges to overwrite the corresponding rows in the main DataSet. ADO.NET compares the primary key values stored in the rows to determine which rows represent the same row of data. By default, ADO.NET overwrites the row in the DataSet whose Merge method you've called. Thus, the changes that the DataAdapter objects make to the dsDelta DataSets are passed along to our main DataSet, and we can handle subsequent updates successfully.

The Component Tray

Before moving on, I want to draw your attention to another feature of the Visual Studio .NET development environment. Developers who've used earlier versions of Visual Studio products might be a little surprised when they look at the designer for the data-bound form in the development environment. One of the first questions that Visual Basic 6 developers ask is, "What is that section below my form?"

If you look below the form in Figure 2-19, you'll see the component tray. Visual Studio .NET allows you to drag items from the Toolbox onto designers. Many developers use the Toolbox to draw buttons on forms. But not all components are visible at run time.

Figure 2-19

The Visual Studio .NET component tray

In Visual Basic 6, for example, you can place timer controls and common dialog box controls on a form. These controls aren't really visible at run time, however. They are components whose properties you can set at design time using the Properties window, but they don't have a visual user interface element. When you place such a control on a form in Visual Basic 6, you see an icon on the form, but when you run the form you don't actually see the control.

Visual Studio .NET places such nonvisual components in the component tray, which is located under the form. To access their properties from the Properties window, you can click items in the component tray. In the new form's components tray, you'll see the items for our DataConnection, DataAdapter, and DataSet objects.

You can drag components from the Data tab of the Toolbox onto the form or the component tray. Some components, such as the DataAdapter, are associated with configuration wizards. Drag an OleDbDataAdapter onto the form, and you'll see a wizard that helps you set properties on your new DataAdapter that allow you to communicate with your database. The wizard generates code based on your input in a similar fashion as the Data Form Wizard. The object variables in your component tray are initialized in a hidden area of the form's code. Open the section of the code marked "Windows Form Designer generated code," shown in Figure 2-20. This section contains all designer-generated code. Scroll down past the object declarations in this region, and you'll see the InitializeComponent procedure that contains the code that the DataAdapter Configuration Wizard generates. Creating components using these rapid application development (RAD) features can save you a great deal of development time.

Figure 2-20

The region of the class that contains "hidden" designer-generated code



Microsoft ADO. NET Core Reference
Microsoft ADO.NET (Core Reference) (PRO-Developer)
ISBN: 0735614237
EAN: 2147483647
Year: 2002
Pages: 104
Authors: David Sceppa

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net