Monday, 08 September 2008
PicoSearch

Data Object Wizard

This column appeared in the February 1999 edition of EXE. It continues the theme started in the January 1999 column concerning the Data Environment Designer.


Sample code and material is available here


Last month I discussed the Data Environment Designer (DED), a tool that allows ADO objects to be defined graphically. Following on with this theme I am now going to introduce the Data Object Wizard (DOW). Whereas the DED is concerned with reducing the amount of code that is needed the DOW works from the opposite principle: it actually writes the code for you.

Available only within the Enterprise edition, this tool actually provides two related functions. The first of these is to provide a Visual Basic class module that is based around a DED command object. This class module then effectively acts as a data source. Once this has been defined the wizard then allows the creation of a User Control which can be applied to a form. We will work through the creation of these components and then examine the results.

Creating a data class

In order to efficiently explain how to use the DOW we will work through an example. Because this article follows on from last month's introduction to the DED we will again make use of the pubs database that is shipped with SQL Server. As a quick reminder, this database contains a simple set of book authors, titles, and publishers, and contains a rudimentary set of test data. Unfortunately it doesn't contain a particularly well-stocked set of stored procedures. If you want to actually try this example yourself you will need to apply a small stored procedure creation file called exvb0299.sql . This file applies basic Select, Insert, Update, and Delete stored procedures (called au_select, au_insert, au_amend, and au_delete respectively) to the authors table.

To get started you should first create a new Visual Basic 6 Data Project. By default this will create a form, a Data Environment, and a Data Report. We won't be using Data Reports in this instance so it can be deleted from the project list if you prefer. Perform the following actions:

  1. Double click the DataEnvironment1 item within the Project Window in order to bring up the DED. Right click on the Connection1 icon and select the Properties menu. Then, as explained in last months article, add the necessary parameters to connect you to your server, making sure that you also include pubs as your target database.

  2. Bring up the Data View window (found in the View menu). If you expand the Connection1 folder, and then the Stored Procedures folder, you should see the four additional stored procedures that were added from our exvb0299.sql file. Sequentially drag each of these stored procedures over to the Connection1 object in the DED. This operation highlights the difference between the two windows: the Data View window contains a snapshot (called Connection1) of the data source defined by the connection parameters, whereas the DataEnvironment window contains the working definition of our data object (also called Connection1). Incidentally, when you add the Insert, Update, and Delete stored procedures you will be asked in each case whether you actually want to execute the command. This occurs because the engine is expecting to find data returned from each procedure, which of course doesn't happen in these cases. I suggest that you choose not to run the command in each of these cases because in doing so you could actually modify the underlying data.

  3. Assuming that the above steps worked ok you can now invoke the Data Object Wizard itself, which can be found under the Add-Ins menu. After the initial introductory page you are asked whether you want to either "create a class object to which other objects can bind data", or to create a "user control object bound to an existing Class object". Select the first of these options.

  4. The wizard will then present you with a tree-view representation of all the DataEnvironment objects that have been created. Click on the au_select stored procedure; this identifies the primary means of obtaining information from the data layer (see Figure 1).

  5. The next page asks which field is the primary key. Change the value of the Primary Key column for the au_id row from No to Yes.

  6. Skip the next item - Define Lookup Table Information - for now. We'll come back to this a little later.

  7. The next three pages ask which stored procedures are to be used to Insert, Update, and Delete data. This is where we select the remaining three custom stored procedures that we added earlier.

  8. The final data-gathering page asks you what name you would like to give to the class; enter Publishers, and then click the Finish button.

Figure 1: Selecting the primary source of data

Although we would expect to see a single class created, the first use of this wizard with the context of a project generates two classes. The expected class - actually called rsclsPublishers - contains the code for manipulating the table, including references to the various stored procedures that we supplied to the wizard. The other class - clsDOW - is required to exist if one or more DOW-generated classes exist and contains the definition for an enum type called EnumSaveMode. This feature offers the ability to globally change the way that ADO saves the data. If the value is set to Immediate then the LockType is set to Optimistic and data is saved when moving the pointer to another RecordSet record. The alternative value, Batch, sets the LockType to BatchOptimistic and determines that data is only saved when the Update method is called.

Space doesn't permit me to reproduce all of the code that is automatically written into the rsclsPublishers class, so I'll just mention the areas that I feel are important. The class contains Get/Let properties for each of the fields specified within the au_select stored procedure, and the expected complement of AddRecord, Delete, Update, and MoveNext/Previous/etc methods. The class also offers four events: ClassError (for general application errors), DeleteRecord (after a record has been deleted), rsMoveComplete (when the RecordSet Move operation has completed), and rsUpdateEvent (when the rsUpdate method has completed). Once this code has been generated Visual Basic doesn't make any attempt to update it later if anything changes so you can safely modify it if you need to. For example, the few places where there is error handling within the class merely passes the problem further up the call chain so this could be a candidate for adding your own, more sophisticated handler. The only caution that I would add to this ability to change the code is to make sure that your underlying data model is stable beforehand. If the stored procedures that the class is based upon are altered then you will probably need to rerun the wizard in order to recreate the class, thereby losing your modifications. The alternative is to manually alter the class code yourself.

I deliberately skipped past the Define Lookup Table Information so as not to cloud the main thrust of the discussion. Returning to this matter now, its purpose is to resolve foreign key relationships to other tables. For example the authors table, which of course predominantly deals with American-format addresses, has a field called state. At run time this field would display the two character short-form of each state, such as CA for California. If the data model were to be altered such that a states table was created which included the short-form field as the primary key and the full name as the other field then the Define Lookup Table Information facility would allow the full state name to be obtained and displayed at run time.

Creating a User Control object

Once the definition has been completed you can return to the wizard and choose to create a User Control that uses our data class as its data source. As before, load the VB6 Data Object Wizard and then:

  1. Select the second option, "A User Control object bound to an existing Class object".

  2. You will be presented with a similar data source screen as shown in Figure 1, but this time displaying the rsclsPublishers class that we have just created (see Figure 2). Click on this class and proceed through the wizard.

  3. You are asked to choose the underlying control that you wish to base your User Control on. This can be a single record (really a collection of text boxes by default), a data grid, a list box, or a combo box. For the purposes of this example choose the single record option.

  4. You are presented here with a list of the fields that will be displayed, along with the facility to change the type of control used for each field. The default control is a text box.

Figure 2: Selecting the class that will act as the data source for the user control

Once you have submitted a name for the control and pressed the Finish button you will see that the new User Control item is displayed on the main Visual Basic toolbox (Figure 3). If you have several of these in a project then the tooltip will tell you which is which. In our particular case accepting a default control name of Publishers actually produces a User Control called uctPublishersSingleRecord1.

Figure 3: The new user control appears on the toolbox

Now that the control is ready for use you can then drag it over to a form as usual. Figure 4 shows a basic form with an instance of the User Control, together with a couple of simple navigation buttons that I added. The Previous button, for example, simply contains the code

uctPublishersSingleRecord1.MovePrevious

to perform the basic navigation.

Figure 4: A form making use of the new user control

Usefulness?

The ability to create a User Control object which can be dragged onto a form in order to display data might seem a little redundant in light of last month's column in which I performed the same thing with the basic DED. The difference comes with the flexibility of the two approaches. The DED method involves a number of controls that are bound to a straightforward Recordset object so if a simple data display is required then this would probably suffice. The DOW-based approach, however, gives you the code for both a data class and a User Control, thereby giving you the starting point for a much greater degree of customisation. Whether the quality and nature of the code is sufficient depends upon your own needs - the initial code certainly wouldn't be robust enough for many corporate applications. One key drawback would be the lack of any support in the initial code for transactions. Some companies have created their own version of this tool for use in the creation of corporate business objects that will produce code that adheres to local coding conventions and error handling methodologies. This is probably a course of action that should be debated in development departments of any size.

Loading the Add-In

Assuming that your Visual Basic 6 installation performed OK then you should find that the Add-Ins management dialog contains the VB6 Data Object Wizard entry, so you should set it as "Loaded". If, however, you are running from a different user profile than the one that the VB installation was performed under then you will find the list of Add-ins curiously depleted. The reason for this is that the installation program writes most configuration data into the HKEY_LOCAL_MACHINE hive of the registry (which is therefore usable to all profiles), but the Add-Ins data is written to HKEY_CURRENT_USER. If you can't see the Add-In then perform the following steps:

Open a Command Prompt window, and change directory to <Visual studio root>\VB98\Wizards.

Run the command regsvr32 msdatobj.dll. This will reapply the registry entry. While you're in here you might like to also run this command on the other DLLs.



 


 

Copyright 2002 Jon Perkins I, Jon Michael Perkins, hereby assert and give notice of my right under section 77 of the Copyright, Designs, and Patents Act 1988 to be identified as the author of the foregoing article.