This section examines the t1 program you just ran. Its purpose is to output the mailing labels for all the customers to a file called t1out.txt.
This code sample shows how to use the classes VVContact and VVContactRepository. For now, ignore the optional argument role, which defaults to an empty string. The line numbers correspond to the comments that follow the code.
#include <rw/db/db.h> //1 #include "conrep.h" //2 #include "tututil.h" //3 RWDBMAIN (MAIN_ARGS_DECL) //4 { associateStreams ("", "t1out.txt", "t1err.txt"); //5 RWDBManager::setErrorHandler (outputStatus); //6 RWCString serverType, serverName, userName, password, databaseName, role; //7 initializeDatabaseArguments (MAIN_ARGS, serverType, serverName, userName, password, databaseName, role); //8 RWDBDatabase aDB = RWDBManager::database (serverType, serverName, userName, password, databaseName, role); //9 VVContactRepository customerPool (aDB, "customer"); //10 customerPool.mailingLabels (outStream); //11 return 0; } //12
Here is a line-by-line description of the program:
//1 | Include the declarations for the DBTools.h++ classes used in this program. |
//2 | Include the declaration for the class VVContactRepository. |
//3 | Include the declarations for the utility routines commonly used by all the tutorials. |
//4 | Rogue Wave is committed to cross-platform development, but window-oriented operating environments make this difficult to do transparently. The two macros used on this line hide differences between Windows and UNIX. If you are interested, you can find the definitions in the tututil.h include file. |
//5 | Again, because of cross-platform development issues, we decided that all input and output for these tutorials should take place to and from files. This is because Windows applications do not necessarily have access to the standard cin, cout, and cerr streams. This function allows file names to be associated with the three streams. The first argument represents input to the program. Since no input from a theoretical user is necessary in this program, an empty string is offered. The second argument is the stream for standard output. The mailing labels go out to this file. The third argument is for error messages. Although associateStreams() is not part of the DBTools.h++ library, it is provided for cross-platform portability of these tutorials. |
//6 | This line sets up an asynchronous error handler. If this program is running, the database reports an error while this program is running, and the function pointed to by outputStatus() is invoked. The function outputStatus() is in tututil.cpp. It checks the severity of the error and decides if the program should be aborted after it sends the error details to a file specified on the previous line. |
//7 | Here, six RWCString instances are declared. They will hold information used in logging into the remote database server. |
//8 | Cross-platform portability issues crop up again on this line. The routine called here places values into the RWCString instances declared on the preceding line. The user of this program can override the default values on the command line. Because different platforms handle command line arguments in different ways, parsing the arguments to determine login information could not be handled uniformly. This routine and the macro MAIN_ARGS hide the complexity of the parsing. The function initializeDatabaseArguments() is not part of the DBTools.h++ library and exists only for the convenience of these tutorials. You can find the definitions in the tututil.h include file. |
//9 | Here an actual connection to a database server is established. The variable aDB will contain the means to access the database defined by arguments to the RWDBManager::database() function. |
//10 | An instance of the class VVContactRepository is created on this line. The first argument, aDB, identifies the database in which the instance's data resides. The second argument identifies the specific table that holds the customer information. |
//11 | The class VVContactRepository contains several useful member functions. The one invoked on this line spools mailing labels out for all customers to the stream specified as the argument. |
//12 | Destructors of all the objects are called here. The database closes automatically along with the output streams. |
This program is really quite short, considering all that it accomplishes. Lines //10 and //11 do most of the work. A detailed examination of the code behind these lines is important for understanding how DBTools.h++ is best used.
Let's look closely at the constructor for VVContactRepository found in the file conrep.cpp. This constructor sets the stage for manipulating the pool of customers.
VVContactRepository::VVContactRepository (const RWDBDatabase& theDB, const RWCString& theTableName) //1 : aDB_(theDB) //2 , table_ (aDB_.table(theTableName)) //3 , nameColumn_ (table_["name"]) //4 , idColumn_ (table_["ID"]) //5 , addressColumn_ (table_["address"]) //6 , cityColumn_ (table_["city"]) //7 , stateColumn_ (table_["state"]) //8 , zipColumn_ (table_["zip"]) //9 , phoneColumn_ (table_["phone"]) //10 { ; //11 }
//1 | The first line simply declares the input parameters: a reference to the database and the name of the table holding the customer data. |
//2 | An instance of VVContactRepository maintains a copy of the database that it is associated with. This initialization makes the association. |
//3 | An instance of VVContactRepository also maintains a table that holds all data. It does this by calling the table() member function of its database object. This function returns an instance of RWDBTable. It is important to note that creating an instance of RWDBTable does not force the RWDBDatabase instance to check the server for the existence of the table. DBTools.h++ accesses the database server only when data is actually manipulated or read. When the table() member function of the class RWDBDatabase instance returns an RWDBTable instance, it is saved by this constructor for future use. |
//4-10 | In these lines, the columns of the table in the database are identified and saved. Most of these columns are not used in this tutorial, but they are important in future exercises. |
//11 | The actual body of the constructor has nothing to do. All the work was done by the initializations. |
Now that the construction of the VVContactRepository instance is complete, the next step in the main routine program was to call the mailingLabels() member function. Here is the source code for VVContactRepository::mailingLabels() from the file conrep.cpp and the description of the code:
VVContactRepository& VVContactRepository::mailingLabels (ostream& o) { //1 RWDBSelector select = aDB_.selector(); //2 select << table_; //3 select.orderBy(nameColumn_); //4 RWDBReader aReader = select.reader(); //5 VVContact aContact; //6 while (aReader()) { //7 aReader >> aContact; //8 aContact.mailingLabel (o); //9 o << endl << endl; //10 } return *this; //11 }
//1 | This line defines the mailingLabels() member function for the class VVContactRepository, which receives an output stream as its argument. |
//2 | The class VVContactRepository kept an associated database named aDB_ in the VVContactRepository constructor. On this line, it uses the database to create an instance of RWDBSelector, which is an object used to select data from a database. |
//3 | An associated table, called table_, was also kept by the constructor. Here the selector is asked to select all the data from table_. In SQL terms, this is like SELECT * from the table. |
//4 | We would like our mailing labels sorted into alphabetical order, so the selector is instructed to orderBy the column in which the customer's name is stored. This column was stored by the constructor in the nameColumn_ variable. This is analogous to the SQL ORDER BY NAME. |
//5 | Here the table is used to create an instance of RWDBReader. A reader can be thought of as both an iterator and a stream. It iterates through the rows of the table that created it, and can stream out the values of the columns in each row. If we had not been concerned with ordering the results, //2-//5 could have been replaced with the single statement RWDBReader aReader = table_.reader(). |
//6 | The table in the database in this tutorial has fields that match the instance variables in the class VVContact. This routine is about to start reading data from the table, and an instance of VVContact is a made-to-order place to store information from that table. This line creates an instance of VVContact to serve as a temporary variable for a single row from the table. |
//7 | A reader is like an iterator. It must be advanced to the next row. Invoking the reader with the operator() member function advances the reader to the next row. If there are no more rows, then operator() returns a zero value and the loop terminates. |
//8 | A reader is also like a stream. Here an entire row of data flows from the reader into the instance of VVContact. An explanation of this can be found in Section 15.5.4. |
//9 | Since the instance of VVContact is now complete, its own member functions can be called. The mailingLabel() member function simply outputs the instance variables for this customer in a form acceptable to the U.S. Postal Service. |
//10 | The mailing labels need to be delimited in some manner, so we add two blank lines. |
//11 | This routine needs to return an instance of VVContactRepository, so it returns itself. At this point, destructors for the VVContact instance and the RWDBReader instance are called. There are no pending rows from the RWDBReader. If there were, they would have quietly and automatically been eliminated here. |
In //8 of the previous code section, a VVContact instance was initialized by shifting out from an RWDBReader instance. This is an important technique and warrants closer examination. Line //8 above actually invokes a global overloading of the operator>>() function involving an RWDBReader on the left and a VVCustomer on the right. The code for this function, found in contact.cpp, follows:
RWDBReader& operator >> (RWDBReader& aReader, VVContact& aContact) { aReader >> aContact.name_ >> aContact.ID_ >> aContact.address_ >> aContact.city_ >> aContact.state_ >> aContact.zip_ >> aContact.phone_; return aReader; }
©Copyright 2000, Rogue Wave Software, Inc.
Contact Rogue Wave about documentation or support issues.