This section examines the Tutorial 2 program you just ran. Its purpose is to write the mailing labels for all customers who are more than seven days overdue to a file called t2out.txt.
This code sample shows the main routine for the tutorial. 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 "rentrep.h" //3 #include "tututil.h" //4 RWDBMAIN (MAIN_ARGS_DECL) //5 { associateStreams ("", "t2out.txt", "t2err.txt"); //6 RWDBManager::setErrorHandler (outputStatus); //7 RWCString serverType, serverName, userName, password, databaseName, role; //8 initializeDatabaseArguments (MAIN_ARGS, serverType, serverName, userName, password, databaseName, role); //9 RWDBDatabase aDB = RWDBManager::database (serverType, serverName, userName, password, databaseName, role); //10 VVContactRepository customerPool (aDB, "customer"); //11 VVRentalTransactionRepository rentalTransactions (aDB, "RentalTransactions"); //12 RWDBColumn customerID = customerPool.idColumn(); //13 RWDBColumn rentalCustomerID = rentalTransactions.customeridColumn(); //14 RWDBColumn dueDate = rentalTransactions.dueDateColumn(); //15 RWDate aWeekAgo; //16 aWeekAgo -= 7; //17 customerPool.mailingLabels (outStream, customerID == rentalCustomerID && dueDate < aWeekAgo); //18 return 1; } //19
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 of the class VVContactRepository. |
//3 | Include the declaration of the class VVRentalTransactionRepository. |
//4 | Include the declarations for the utility routines used by all the tutorials. |
//5-9 | These lines are for initialization and multiplatform portability. They are common to all the tutorials, and are explained in the comments in Section 15.5.1. |
//10 | Here an actual connection to a database server is established. The variable aDB will serve as a means to access the database defined by arguments to the RWDBManager::database() function. |
//11 | 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 name of the specific table that holds the customer information. This constructor was explained in detail in Tutorial 1. |
//12 | An instance of the class VVRentalTransactionRepository is created on this line. The first argument, aDB, identifies the database in which instance's data resides. The second argument identifies the specific table that holds the rental transaction information. The constructor invoked here is quite simple and parallels the VVContactRepository constructor. |
//13 | //13 Here an instance of RWDBColumn that represents the ID column of the customer table is created. This instance will be used in creating a predicate to be used in a criterion for the selection. The idColumn() member function of the class VVContactRepository returns the column instance created in the VVContactRepository constructor. |
//14 | Here an instance of RWDBColumn representing the customerID column of the customer table is created. The idColumn() member function of the class VVRentalTransactionRepository returns the column instance created in the VVRentalTransactionRepository constructor. |
//15 | Here an instance of RWDBColumn representing the dueDate column of the customer table is created. |
//16 | This instance of RWDate is automatically initialized to today. |
//17 | Subtracting seven from the current date yields the date a week ago. |
//18 | Here the mailingLabels() member function of the class VVContactRepository is exploited. It accepts a reference to an output stream and an RWDBCriterion. The criterion is created anonymously by using overloaded relational operators on RWDBColumn instances. The result is the predicate that will be used in selecting the appropriate data from the customer table. |
//19 | Destructors for all the objects are called here. The database closes automatically along with the output streams. |
The invocation of the mailingLabels() member function on //18 above does most of the work in this tutorial. The source code of this member function, from the file conrep.cpp is shown here:
VVContactRepository& VVContactRepository::mailingLabels (ostream& o, const RWDBCriterion& criterion) //1 { RWDBReader aReader = reader(criterion); //2 VVContact aContact; //3 while (aReader()) { //4 aReader >> aContact; //5 aContact.mailingLabel (o); //6 o << endl << endl; //7 } return *this; //8 }
//1 | This line defines the mailingLabels() member function for the class VVContactRepository. It receives an output stream as its first argument and an RWDBCriterion as its second argument. |
//2 | The reader() member function of the class VVContactRepository is invoked here. It receives an RWDBCriterion as its argument and returns an RWDBReader. This reader is associated with a stream of information coming from the server that returns only the records that match the criterion. |
//3 | The database table used 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 the table. This line creates an instance of VVContact to serve as a temporary variable for storing a single row from the table. |
//4 | 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. |
//5 | 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. |
//6 | Since the instance of VVContact is 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. |
//7 | The mailing labels need to be delimited in some manner, so we add two blank lines. |
//8 | 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 were no pending rows from the RWDBReader. If there were, they would have quietly and automatically eliminated. |
Line //2 above invokes the reader() member function of VVContactRepository. The definition of the function called on //2 is shown below. This function actually creates the query and submits it to the database. It then returns an RWDBReader instance that can be used to get results back from the server.
RWDBReader VVContactRepository::reader (const RWDBCriterion& criterion) //1 { RWDBSelector s = aDB_.selector(criterion); //2 s.distinct(); //3 s << table_; //4 return s.reader(); //5 }
//1 | This line defines the reader() member function for the class VVContactRepository. It accepts one argument: a criterion to be used in determining which records to return from the customer table. |
//2 | s is an instance of RWDBSelector, an encapsulation of an SQL SELECT expression. It is produced and therefore associated with an instance of RWDBDatabase. This particular instance of RWDBDatabase, aDB_, was saved by the VVContactRepository constructor. In RWDBSelector's constructor, it uses one argument. This argument represents the predicate to be used in the WHERE clause of the select expression. In this case, the RWDBCriterion passed in eventually translates into a predicate that is functionally equivalent to:
customer.ID = RentalTransactions.customerID AND RentalTransactions.dueDate < `5/4/94' |
//3 | This line adds an additional requirement that all results must be distinct; in other words, no duplicates should be returned. This is added because only a single row is required for each contact selected. This is functionally equivalent to: SELECT DISTINCT ... |
//4 | An RWDBSelector instance can select a variable number of columns or expressions. To reflect this indeterminate number of arguments, operator<<() was chosen to specify the SELECT clause. Instances of RWDBColumn can be shifted into the selector. In this case, all the columns are selected by shifting an RWDBTable instance into the selector. Here table_ is the RWDBTable instance associated with the customer table saved by the VVContactRepository constructor. The effect is to create the equivalent to an SQL SELECT customer.* expression. |
//5 | Fetching an instance of RWDBReader from a selector submits the query to the database. The selector has sufficient information to generate the appropriate SQL statement. The reader created here by the RWDBSelector instance is returned immediately by this member function. |
©Copyright 2000, Rogue Wave Software, Inc.
Contact Rogue Wave about documentation or support issues.