dtl


RandomDBView<DataObj, ParamObj>

Category: containers Component type: type

Description

RandomDBView is a Random Access Container with the property that elements are bound to an underlying database. Rows in the table can be accessed and modified using random access iterators provided by the container. To provide random access to the elements in the table, the container uses an ODBC static cursor to guarantee a particular ordering for the rows. Rows can be inserted or deleted from the table by using the insert() and erase() methods. The specifics of how rows are updated or deleted can be controlled by the user via the SetKey() method which specifies what kind of key to use when updating or deleting rows. Please note that when making changes to the table via insert(), erase() or the non-const iterator, these changes will not be visible until the ReQuery() method is called (see [1] for details).

Definition

Defined in the RandomDBView.h header file.

Refinement of

Random Access Container

Associated types

The types defined by Random Access Container .

Example 1 :

//Create a quick DBView called db_example.

//Rows in this view will be of type db_example_row.

//See DTL_TABLE for details.

DTL_TABLE3(db_example,

   int, int_value,

   string, string_value,

   double, double_value

);





// Random access container example

void RandomDBViewExample()

{

   RandomDBView<db_example_row> view(db_example);



   cout << "Objects read from DB:" << endl;

   copy(view.begin(), view.end(), ostream_iterator<db_example_row>(cout, "\n"));



   cout << "\nElements in reverse order:" << endl;

   copy(view.rbegin(), view.rend(), ostream_iterator<db_example_row>(cout, "\n"));



   // modify the third row in the table

   RandomDBView<db_example_row>::iterator it = view.begin();

   db_example_row row(it[2]);

   row.int_value++;

   *it = row;

   

   // NOTE THAT FOR THE MODIFIED ROW TO SHOW UP WE MUST CALL ReQuery().

   // Note that there is no guarantee that the third row will show the updated record,

   // since other users may have modified the database or the DB may return records in a different

   // order.  See the ReQuery() function for details.

   cout << "Show updated result row:" << endl;

   view.ReQuery();

   cout << it[2] << endl;

 

   // show distance functions 

   cout << "Distance from first to last: " << view.end() - view.begin() << endl;

   cout << "Container size: " << view.size() << endl;



   // insert and delete rows

   db_example_row row_insert(it[2]);

   row_insert.int_value = 666;

   view.insert(row_insert);

   view.erase(it+(ptrdiff_t)2);

   cout << "Show result set with inserted/deleted row:" << endl;

   view.ReQuery();

   copy(view.begin(), view.end(), ostream_iterator<db_example_row>(cout, "\n"));



   // show container comparison operators

   RandomDBView<db_example_row> view2(view);

   cout << boolalpha;

   cout << "view == view2 : " << (view == view2) << endl;

   cout << "view < view2 : " << (view < view2) << endl;

}

Example 2 :

// Random access DBView built from a DynamicDBView

void RandomDynamicDBView()

{

	DynamicDBView<> dynamic_view("DB_EXAMPLE", "*");

	RandomDBView<variant_row, variant_row> random_view(dynamic_view);



	cout << "Items from DB:" << endl;

	copy(random_view.begin(), random_view.end(), ostream_iterator<variant_row>(cout, "\n"));

	cout << "\n\n";



	cout << "Items from DB in reverse order:" << endl;

	copy(random_view.rbegin(), random_view.rend(), ostream_iterator<variant_row>(cout, "\n"));



	// insert and delete rows

	variant_row row_insert(random_view[2]);

	row_insert["INT_VALUE"] = 666;

	random_view.insert(row_insert);

	random_view.erase(random_view.begin()+(ptrdiff_t)2);

	cout << "Show result set with inserted/deleted row:" << endl;

	random_view.ReQuery();

    	copy(random_view.begin(), random_view.end(), ostream_iterator<variant_row>(cout, "\n"));

}

Public Base Classes

RandomDBView

Template parameters

Parameter Description Default
DataObj The type of object that will be written to the RandomDBView. This object will be bound through use of the BCA to the appropriate columns in the database.  
ParamObj The type of object that will be used to specify the postfix parameters to the RandomDBView. DefaultParamObj<DataObj> 

 

Associated types

As defined in a Random Access Container .

 

Expression semantics

Name Expression Precondition Semantics Postcondition
Main constructor
RandomDBView(const DBView<DataObj, ParamObj>)
  Creates a random access container bound to a table as specified using a DBView to control the paramaters.  

 

New Members

These members are not defined in the Random Access Container requirements but are specific to RandomDBView. Set the list of fields which represents the key for the row. All rows which match the key fields for the old value of the row get updated if the iterator is assigned a new value. (i.e. typical output iterator behaviour *output_iterator = new_value; output_iterator++; In this case assignment triggers an update operation against the database. ) KeyFields is a comma separated list of the key fields that the iterator is to use when updating the table: "field1, field2, ..., fieldN". If this function is not called on the select_update_iterator, then the select_update_iterator will attempt to automatically determine a unique identifier for rows in the table using the autokeys functionality. See Key Mode for more details.
Member Where defined Description
RandomDBView(const DBView<DataObj, ParamObj>)
RandomDBView Creates a random access container bound to a table as specified using a DBView to control the paramaters.
void insert(const DataObj& x) RandomDBView Inserts x. The inserted element will not be visible until ReQuery() is called.
template <class InputIterator> void insert(InputIterator first, InputIterator last) RandomDBView Inserts the range [first, last). The inserted elements will not be visible until ReQuery() is called.
void erase(iterator pos) RandomDBView Erases the element at position pos. The erased element will not be removed until ReQuery() is called.
void erase(iterator first, iterator last) RandomDBView Erases the elements in the range [first, last). The erased elements will not be removed until ReQuery() is called.
void ReQuery() RandomDBView Close the static ODBC cursor used by the random access iterators. Force re-query of the database to reflect updated/inserted/deleted records by this and other users. Note that ReQuery() will affect any copies made of the RandomDBView since these copies will point to the same ODBC cursor. After a ReQuery() operation any active iterators against the container will be invalidated in the following sense. Iterators that were created prior to a ReQuery() will continue to point to the same row number in the recordset, but this does not gurantee that they will have the same meaning as before. Why? Because after a ReQuery(), rows may be added/deleted/updated in the result set. Also, after a ReQuery(), there is no guarantee that the database will return records in the same order that it did before (although it most likely will, but if you need to guarantee an order then it would be best to add a unique ORDER BY clause to your query).
void SetKey(const tstring &KeyFields) RandomDBView Set the key fields to use when updating or erasing records from the table. Argument is a comma delimited list of fields "field1, field2, ..., fieldN". Note that this will override the default set of key fields that were specified in the DBView that was used to create the RandomDBView. By default, the container will attempt to automatically determine a unique identifier for rows in the table using the autokeys functionality. See Key Mode for more details.

Members

Member Where defined Description
value_type Container The type of object, DataObj, stored in the RandomDBView.
pointer Container Pointer to DataObj.
reference Container Reference to DataObj
const_reference Container Const reference to DataObj
size_type Container An unsigned integral type.
difference_type Container A signed integral type.
iterator Container Iterator used to iterate through a RandomDBView. Please note that if changes are made to the table via this iterator, the changes will not be visible until the ReQuery() method is called. This means that algorithms which read back changes they have made to the container will not work with this iterator. See [1]
const_iterator Container Const iterator used to iterate through a RandomDBView.
reverse_iterator Reversible Container Iterator used to iterate backwards through a RandomDBView. Please note that if changes are made to the table via this iterator, the changes will not be visible until the ReQuery() method is called. This means that algorithms which read back changes they have made to the container will not work with this iterator. See [1]
const_reverse_iterator Reversible Container Const iterator used to iterate backwards through a RandomDBView.
iterator begin() Container Returns an iterator pointing to the beginning of the RandomDBView.
iterator end() Container Returns an iterator pointing to the end of the RandomDBView.
const_iterator begin() const Container Returns a const_iterator pointing to the beginning of the RandomDBView.
const_iterator end() const Container Returns a const_iterator pointing to the end of the RandomDBView.
reverse_iterator rbegin() Reversible Container Returns a reverse_iterator pointing to the beginning of the reversed RandomDBView.
reverse_iterator rend() Reversible Container Returns a reverse_iterator pointing to the end of the reversed RandomDBView.
const_reverse_iterator rbegin() const Reversible Container Returns a const_reverse_iterator pointing to the beginning of the reversed RandomDBView.
const_reverse_iterator rend() const Reversible Container Returns a const_reverse_iterator pointing to the end of the reversed RandomDBView.
size_type size() const Container Returns the size of the RandomDBView.
size_type max_size() const Container Same as size().
bool empty() const Container true if the RandomDBView's size is 0.
const_reference operator[](size_type n) const Random Access Container Returns the n'th element.
RandomDBView(const DBView & view) RandomDBView Creates a RandomDBView using the table and parameters specified by the given DBView.
RandomDBView(const RandomDBView&) Container The copy constructor.
~RandomDBView() Container The destructor.
RandomDBView& operator=(const RandomDBView&) Container The assignment operator
void swap(RandomDBView&) Container Swaps the contents of two RandomDBViews.
bool operator==(const RandomDBView&, 

                const RandomDBView&)

Forward Container Tests two RandomDBViews for equality.
bool operator<(const RandomDBView&, 

               const RandomDBView&)

Forward Container Lexicographical comparison.
bool operator>(const RandomDBView&, 

               const RandomDBView&)

Forward Container Lexicographical comparison.
bool operator<=(const RandomDBView&, 

               const RandomDBView&)

Forward Container Lexicographical comparison.
bool operator>=(const RandomDBView&, 

               const RandomDBView&)

Forward Container Lexicographical comparison.
void insert(const DataObj& x) RandomDBView Inserts x. The inserted element will not be visible until ReQuery() is called.
template <class InputIterator> void insert(InputIterator first, InputIterator last) RandomDBView Inserts the range [first, last). The inserted elements will not be visible until ReQuery() is called.
void erase(iterator pos) RandomDBView Erases the element at position pos. The erased element will not be removed until ReQuery() is called.
void erase(iterator first, iterator last) RandomDBView Erases the elements in the range [first, last). The erased elements will not be removed until ReQuery() is called.
void ReQuery() RandomDBView Close the static ODBC cursor used by the random access iterators. Force re-query of the database to reflect updated/inserted/deleted records by this and other users. Note that ReQuery() will affect any copies made of the RandomDBView since these copies will point to the same ODBC cursor. After a ReQuery() operation any active iterators against the container will be invalidated in the following sense. Iterators that were created prior to a ReQuery() will continue to point to the same row number in the recordset, but this does not gurantee that they will have the same meaning as before. Why? Because after a ReQuery(), rows may be added/deleted/updated in the result set. Also, after a ReQuery(), there is no guarantee that the database will return records in the same order that it did before (although it most likely will, but if you need to guarantee an order then it would be best to add a unique ORDER BY clause to your query).
void SetKey(const tstring &KeyFields) RandomDBView Set the key fields to use when updating or erasing records from the table. Argument is a comma delimited list of fields "field1, field2, ..., fieldN". Note that this will override the default set of key fields that were specified in the DBView that was used to create the RandomDBView. By default, the container will attempt to automatically determine a unique identifier for rows in the table using the autokeys functionality. See Key Mode for more details.

[1] RandomDBView design

When we designed RandomDBView we built the container to work against a "static ODBC scrollable cursor" as the underlying cursor for retrieving rows. Using such a cursor gives us a defined and repeatable ordering for the records which was what we needed to obtain random access iterators. Unfortunately, static ODBC cursors have the limitation that if you try to update records directly via the cursor, some ODBC drivers will show the updated records but other drivers will not. To avoid amiguity, we had the container apply updates via an independently executed query so that we could specify how changes would show up rather than having the behavior be ODBC driver dependent. Unfortunately, this means that our non-const random iterators are not quite standard compliant since changes don't show up until a special ReQuery() method is called.

One possible solution to this problem would be to add logging to the container. The idea here would be that when users make a change to a row, we log the updated row. Then, when the iterator goes to retrieve a row via operator * we would simply check whether a more recent version of the row exists in the change log and show it rather than the original. The problems with this approach are twofold:

  1. It slows down record access for users that don't want logging.
  2. If a lot of records are changed, potentially the log could become as large as the entire table. This sort of defeats the idea of RandomDBView because if the table can be easily held in memory why not just fetch the whole thing into a container or an IndexedDBView?
So, we might eventually add logging to the container, but if we do it would be as an optional template paramter where the code/overhead would not be compiled into the container for users that don't want it.

See also

Random Access Container, DBView


[DTL Home]

Copyright 2002, 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.

SourceForge Logo

This site written using the ORB. [The ORB]