The Program
This section examines the t7 program, which writes a number of invoices to a file called t7out.txt. Each invoice represents a customer renting one or more videos from the video store.
The Main Routine
The following is the main routine for the tutorial. The line numbers correspond to the comments that follow the code.
#include <rw/db/db.h> //1
#include "tututil.h" //2
#include "invoice.h" //3
int main(int argc, char** argv) //4
{
associateStreams("t7in.dat", "t7out.txt", "t7err.txt"); //5
RWDBManager::setErrorHandler(outputStatus); //6
RWCString serverType, serverName, userName,
password, databaseName, pstring; //7
initializeDatabaseArguments(argc, argv, serverType,
serverName, userName, password,
databaseName, pstring); //8
RWDBDatabase aDB = RWDBManager::database(serverType, serverName,
userName, password,
databaseName,pstring); //9
if( aDB.isValid() )
{
unsigned long aCustomerID; //10
unsigned long aVideoID; //11
while (!inStream.eof()
&& !inStream.bad() && !inStream.fail()) { //12
inStream >> aCustomerID; //13
if (!inStream.eof()
&& !inStream.bad() && !inStream.fail()) //14
// create an invoice
VVInvoice aInvoice(aCustomerID, aDB); //15
// add each video rental
do { //16
inStream >> aVideoID; //17
if (aVideoID) { //18
aInvoice.addRental(aVideoID); //19
}
} while (aVideoID); //20
// print the invoice
aInvoice.print(); //21
}
}
}
closeStreams("t7in.dat", "t7out.txt", "t7err.txt");
return 0; //22
} //23
Here is a line-by-line description of the program:
VVInvoice::addRental
The invocation of the addRental() function inserts new data into the rentals table and updates the videos table. The source code of this member function can be found in the source file invoice.cpp.
void
VVInvoice::addRental(unsigned long aVideoID) //1
{
RWDBConnection dbSession = aDB_.connection(); //2
dbSession.beginTransaction(); //3
RWDateTime rentalDate(9,6,2000); //4
// due date is three(3) days from default
RWDateTime dueDate(rentalDate); //5
dueDate = dueDate + (3 * RWDateTime::millisecsInDay); //6
// returnDate is not assigned now, so make it invalid
RWDateTime returnDate; //7
// add a rental transaction
VVRentalTransactionRepository rentals(aDB_, rentalTableName); //8
VVRentalTransaction aRental(aCustomerID_, aVideoID,
aInvoiceID_, rentalDate,
dueDate, returnDate); //9
rentals.insert(aRental, dbSession); //10
// update video inventory
VVVideoRepository videos(aDB_, videoTableName); //11
VVVideo aVideo("", aVideoID, 0, "", 0, 0, ""); //12
aVideo = videos.find(aVideo); //13
if (aVideo.numOnHand() > 0) //14
aVideo.numOnHand(aVideo.numOnHand() - 1); //15
videos.update(aVideo, aVideo, dbSession); //16
// commit the transaction
dbSession.commitTransaction(); //17
}
VVVideoRepository::find
The find() member function of the class VVVideoRepository, takes a VVVideo instance as an argument, with only some of its fields filled in. It uses this partial VVVideo as a search criterion. The function returns the first video it finds that matches the field passed in. The source code of this member function follows, taken from the file vidrep.cpp.
VVVideo
VVVideoRepository::find(const VVVideo& aVideo) const //1
{
RWDBCriterion searchCriterion("0 = 0", 0, 0); //2
RWCString title = aVideo.title(); //3
if (!title.isNull()) //4
searchCriterion = searchCriterion &&
titleColumn_.like(title); //5
if (aVideo.id()) //6
searchCriterion = searchCriterion &&
idColumn_ == aVideo.id(); //7
if (aVideo.year()) //8
searchCriterion = searchCriterion &&
yearColumn_ == aVideo.year(); //9
RWCString category = aVideo.category(); //10
if (!category.isNull()) //11
searchCriterion = searchCriterion &&
categoryColumn_.like(category); //12
if (aVideo.quantity())
searchCriterion = searchCriterion &&
quantityColumn_ == aVideo.quantity(); //13
if (aVideo.numOnHand()) //14
searchCriterion = searchCriterion &&
numOnHandColumn_ == aVideo.numOnHand(); //15
RWCString synopsis = aVideo.synopsis(); //16
if (!synopsis.isNull()) //17
searchCriterion = searchCriterion &&
synopsisColumn_.like(synopsis); //18
RWDBSelector aSelector = aDB_.selector(searchCriterion); //19
aSelector << table_; //20
RWDBReader aReader = aSelector.reader(); //21
VVVideo theVideo; //22
if (aReader()) //23
aReader >> theVideo; //24
return theVideo; //25
NOTE >> Do not confuse the RWCString::isNull method with NULL database values. The RWCString::isNull method returns true if the string is empty. However, some database vendors do not consider an empty string to be the same as a NULL value.
VVVideoRepository::update
The
update() member function of
VVVideoRepository accepts three parameters, first two of which are instances of
VVVideo. The first instance identifies the record to be changed, while the second instance is used as new information. The third parameter is an instance of
RWDBConnection which is used to execute the update.
VVVideoRepository&
VVVideoRepository::update(const VVVideo& originalVideo,
const VVVideo& newVideo,
const RWDBConnection& aConnection) //1
{
RWDBUpdater anUpdater = table_.updater(); //2
anUpdater.where(idColumn_ == originalVideo.id()); //3
anUpdater << titleColumn_.assign(newVideo.title())
<< idColumn_.assign(newVideo.id())
<< yearColumn_.assign(newVideo.year())
<< categoryColumn_.assign(newVideo.category())
<< quantityColumn_.assign(newVideo.quantity())
<< numOnHandColumn_.assign(newVideo.numOnHand())
<< synopsisColumn_.assign(newVideo.synopsis()); //4
anUpdater.execute(aConnection); //5
return *this;
}