dtl


DBView<DataObj, ParamObj>

Category: containers Component type: type

Description

The DBView Container is a semi-Container with the property that elements are bound to an underlying database. We say that DBView is a semi-Container because it implements all properties and methods of an STL container except for the empty(), size() and max_size() methods. We do not implement empty(), size() or max_size() for this container because we cannot guarantee invariance for these functions; e.g. after a programmer calls the size() function a second user may insert more records into the database on the back-end, therby invalidating the fixed count the programmer might expect.

Definition

Defined in the DBView.h header file.

Refinement of

semi-Container

Associated types

The types defined by Container and the additional iterator types listed below.

Example 1 :

Accessing a Table in Four Easy Steps:


1. Define an object to hold the rows from your query.

2. Define an association between fields in your query and fields in your object. This is what we call a 'BCA', which is short for Bind Column Addresses. In the example below, this is done via the functor "BCAExample". The job of the BCA is to equate SQL fields with object fields via the '==' operator which will then establish ODBC bindings to move data to or from a user query.

3. Create a view to select records from. This view is built from the template DBView and establishes which table(s) you want to access, what fields you want to look at (via the BCA), and an optional where clause to further limit the set of records that you are working with. The DBView template forms a semi-Container in the STL sense.1.

4. Use the DBView container to obtain an iterator to SELECT, INSERT, UPDATE or DELETE records from your view. These iterators may be used to either populate STL containers or apply algorithms from the Standard Template library.


In all the examples that follow we will assume that our database contains a table called DB_EXAMPLE of the form

SQL> desc db_example;
Name                            Type
------------------------------- --------
INT_VALUE                       INTEGER
STRING_VALUE                    VARCHAR
DOUBLE_VALUE                    FLOAT
EXAMPLE_LONG                    INTEGER
EXAMPLE_DATE                    DATE

// STEP 1 ////
// "Example" class to hold rows from our database table
class Example
{
  public:                                // tablename.columnname:
	int exampleInt;                 // DB_EXAMPLE.INT_VALUE
	string exampleStr;              // DB_EXAMPLE.STRING_VALUE
	double exampleDouble;           // DB_EXAMPLE.DOUBLE_VALUE
	long exampleLong;               // DB_EXAMPLE.EXAMPLE_LONG
	TIMESTAMP_STRUCT exampleDate;   // DB_EXAMPLE.EXAMPLE_DATE

	Example(int exInt, const string &exStr, double exDouble, long exLong,
		const TIMESTAMP_STRUCT &exDate) :
	   exampleInt(exInt), exampleStr(exStr), exampleDouble(exDouble), exampleLong(exLong),
	   exampleDate(exDate)
	{ }

};

// STEP 2 ////
// Create an association between table columns and fields in our object
template<> class dtl::DefaultBCA<Example>
{
public:
	void operator()(BoundIOs &cols, Example &rowbuf)
    	{
	   cols["INT_VALUE"] == rowbuf.exampleInt;
	   cols["STRING_VALUE"] == rowbuf.exampleStr;
	   cols["DOUBLE_VALUE"] == rowbuf.exampleDouble;
	   cols["EXAMPLE_LONG"] == rowbuf.exampleLong;
	   cols["EXAMPLE_DATE"] == rowbuf.exampleDate;
	}
}

// STEP 3 & 4
// Read the contents of the DB_EXAMPLE table and return a vector of the
// resulting rows
vector<Example> ReadData() {
	// Read the data
	vector<Example> results;
	DBView<Example> view("DB_EXAMPLE");

	DBView<Example>::select_iterator read_it = view.begin();
	for ( ; read_it != view.end();  read_it++)
	{
		results.push_back(*read_it);
	}
	return results;
}

1 See http://www.sgi.com/tech/stl/Container.html for the definition of an STL container, we call DBView a semi container because it supports all standard container methods except size(), max_size() and empty(). We explain why these were left out by design in the documentation for the DBView template.

Example 2:

//BPA Functor to bind SQL parameters to a data object

// "Example" class to hold rows from our database table
class Example
{
  public:                                // tablename.columnname:
	int exampleInt;                 // DB_EXAMPLE.INT_VALUE
	string exampleStr;              // DB_EXAMPLE.STRING_VALUE
	double exampleDouble;           // DB_EXAMPLE.DOUBLE_VALUE
	long exampleLong;               // DB_EXAMPLE.EXAMPLE_LONG
	TIMESTAMP_STRUCT exampleDate;   // DB_EXAMPLE.EXAMPLE_DATE

	Example(int exInt, const string &exStr, double exDouble, long exLong,
		const TIMESTAMP_STRUCT &exDate) :
	   exampleInt(exInt), exampleStr(exStr), exampleDouble(exDouble), exampleLong(exLong),
	   exampleDate(exDate)
	{ }

};

// Create an association between table columns and fields in our object
class BCAExampleObj
{
public:
	void operator()(BoundIOs &cols, Example &rowbuf)
    	{
	   cols["INT_VALUE"] == rowbuf.exampleInt;
	   cols["STRING_VALUE"] == rowbuf.exampleStr;
	   cols["DOUBLE_VALUE"] == rowbuf.exampleDouble;
	   cols["EXAMPLE_LONG"] == rowbuf.exampleLong;
	   cols["EXAMPLE_DATE"] == rowbuf.exampleDate;
	}
}

class ExampleParamObj
{
    public:
       	int lowIntValue;
	int highIntValue;
	string strValue;
	TIMESTAMP_STRUCT dateValue;
};

class BPAParamObj
{
public:
	void operator()(BoundIOs &boundIOs, ExampleParamObj &paramObj)
	{
	  boundIOs[0] == paramObj.lowIntValue;
	  boundIOs[1] == paramObj.highIntValue;
	  boundIOs[2] == paramObj.strValue;
	  boundIOs[3] == paramObj.dateValue;
	}

};

// read some Example objects from the database and return a vector of
// the results, use BPA to set join parameters
vector<Example> ReadData()
{
	vector<Example> results;

	// construct view
	
	DBView<Example, ExampleParamObj>
		view("DB_EXAMPLE", BCAExampleObj(),
		"WHERE INT_VALUE BETWEEN (?) AND (?) AND "
		"STRING_VALUE = (?) OR EXAMPLE_DATE < (?) ORDER BY EXAMPLE_LONG",
		BPAParamObj());

	// loop through query results and add them to our vector
	// in this loop, read_it.GetLastCount() records read from DB

	DBView<Example, ExampleParamObj>::select_iterator read_it = view.begin();

	// set parameter values for the WHERE clause in our SQL query
	read_it.Params().lowIntValue = 2;
	read_it.Params().highIntValue = 8;
	read_it.Params().strValue = "Example";
	
	TIMESTAMP_STRUCT paramDate = {2000, 1, 1, 0, 0, 0, 0};
	read_it.Params().dateValue = paramDate;

	for ( ; read_it != view.end();  read_it++)
	{
		cout << "Reading element #" << read_it.GetLastCount() << endl;
		results.push_back(*read_it);

		cout << "read_it->exampleInt = " << read_it->exampleInt << endl;
		cout << "read_it->exampleStr = " << read_it->exampleStr << endl;
		
	}
	
	return results;
}

Example 3:

// Using a DBView to insert rows into a database


// ... Class definitions for Example and BCAExample as per our ReadData example .....

// Specialization of DefaultInsValidate for Example
// This defines a business rule we wish to enforce for all 
// Example objects before they are allowed to be inserted into the database
template<> class dtl::DefaultInsValidate<Example> 
{
public:

	bool operator()(Example &rowbuf) {	
		// data is valid if rowbuf.exampleStr is nonempty and
		// rowbuf.exampleDouble is 
		// between 0 and 100 (like a percentage)
		return (rowbuf.exampleStr.length() > 0 &&  rowbuf.exampleDouble >= 0.0 
			&& rowbuf.exampleLong  <= 100.0);
	}
};


// Insert rows from the vector<Example> parameter into the database
void WriteData(const vector<Example> &examples)
{
	DBView<Example> view("DB_EXAMPLE");

	// loop through vector and write Example objects to DB
	// write_it.GetCount() records written in loop

	DBView<Example>::insert_iterator write_it = view;

	for (vector<Example>::const_iterator ex_it = examples.begin(); ex_it != examples.end(); ex_it++, write_it++)
	{
		*write_it = *ex_it;
	 	cout << "Writing element #" << write_it.GetCount() + 1<< endl;
	}
}

Public Base Classes

None.

Template parameters

Parameter Description Default
DataObj The type of object that will be written to the DBView. This object will be bound through use of the BCA to the appropriate columns in the database. The set of value types of an DBView::insert_iterator consists of a single type, DataObj.  
ParamObj The type of object that will be used to specify the postfix parameters to the DBView. DefaultParamObj<DataObj> 

 

Notation

X A type that is a model of DBView
a Object of type X
t Object of type X::value_type
p, q Object of type X::iterator

 

Associated types

In addition to the types defined in a semi-Container , the following types are defined.:

Iterator type X::select_iterator An input iterator to read records from the view
Iterator type X::insert_iterator An output iterator to insert records into the view
Iterator type X::update_iterator An output iterator to update records in the view
Iterator type X::delete_iterator An ouput iterator to delete records from the view

 

Expression semantics

Name Expression Precondition Semantics Postcondition
Default constructor
X a(const string &tableList, 
const BCA &bca_functor = DefaultBCA<DataObj>(),
const string &postfix = "", 
const BPA &bpa_functor = DefaultBPA<ParamObj>(),
const SelVal sel_val = DefaultSelVal<DataObj>(),
const InsVal ins_val = DefaultInsVal<DataObj>(),
DBConnection &connection = DBConnection::GetDefaultConnection())
  Creates an empty container bound to a table, using the database connection specified in the connection object. The actual queries run againt this table are built by the select, insert, update and delete iterators (see these iterators for details) but essentially follow the following format:

"SELECT " + <columns listed in bca_fn()> + " FROM " + tableList + postfix

In the SQL clause, users may also specify dynamic parameters through the use of SQL '(?)' syntax. In this case BPA is a class that is used to hold these runtime parameters and bpa_functor is a functor used to associate fields in the parameters class with parameter fields in the query.

The size of the container is 0. Rows are operated on by obtaining the appropriate iterator from the container.

 

Members

Member Where defined Description
value_type Container The type of object, T, stored in the DBView. In this case T = DataObj
pointer Container Pointer to T.
reference Container Reference to T
const_reference Container Const reference to T
size_type Container An unsigned integral type.
difference_type Container A signed integral type.
iterator Container Iterator used to iterate through a DBView. The default iterator for DBView is the select_iterator.
const_iterator Container Const iterator used to iterate through a DBView. (iterator and const_iterator are the same type.)
reverse_iterator Reversible Container Iterator used to iterate backwards through a DBView.
const_reverse_iterator Reversible Container Const iterator used to iterate backwards through a DBView. (Reverse_iterator and const_reverse_iterator are the same type.)
iterator begin() Container Returns an iterator pointing to the beginning of the DBView.
const_iterator begin() const Container Returns a const_iterator pointing to the beginning of the DBView.
iterator end() Container Returns a const_iterator pointing to the end of the DBView.
const_iterator end() const Container Returns a const_iterator pointing to the end of the DBView.
X a(const string &tableList, 
const BCA &bca_functor = DefaultBCA<DataObj>(),
const string &postfix = "", 
const BPA &bpa_functor = DefaultBPA<ParamObj>(),
const SelVal sel_val = DefaultSelVal<DataObj>(),
const InsVal ins_val = DefaultInsVal<DataObj>(),
DBConnection &connection = DBConnection::GetDefaultConnection())
Container Creates an empty DBView.
DBView(const DBView&) Container The copy constructor.
DBView& operator=(const DBView&) Container The assignment operator
void set_io_handler(IOHandler<DataObj, ParamObj>) DBView Sets the IOHandler for this view. Iterators created from this view will then use this handler by default until set by the iterator's version of this method. The IOHandler will try to handle exceptions thrown by such iterators and tell the code which caught the exception whether to suppress the error or still throw.
template<class UserHandler> const UserHandler & get_io_handler(UserHandler *dummy) const DBView Returns the current IOHandler for this object cast to the actual type of the handler based on the dummy pointer passed in. If the dynamic cast of the IOHandler object fails, an exception will be thrown.
IOHandler<DataObj, ParamObj> &get_io_handler() const DBView Returns the current IOHandler for this object as a raw IOHandler object. You must cast to the actual type of the handler to be able to access any of your handler's public members.
void swap(DBView&) Container Swaps the contents of two DBView's.

See also

Multiple Associative Container, BCA, BPA, InsVal, SelVal, DB_iterator


[DTL Home]

Copyright © 2001, Michael Gradman and Corwin Joy.

Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appears in all copies and that both that copyright notice and this permission notice appear in supporting documentation. Corwin Joy and Michael Gradman make no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty.