C++ Object-Oriented Database Generator

Shown here is the application that generates CObject and CObList derived classes for Object-Oriented database management.

Some of the projects I have been working on lately have made extensive use of CObject derived classes for encapulated data management (Object-Oriented Databases). After creating only a few data objects, you begin to realize that the production of much of the code could be automated. This project is a code generator to produce CObject-dervied data classes with serialization and protected data members.

In addition to the CObject derived data classes, the application can also generate a sorted CObList derived class to hold your data objects. For each data object you create, you can specify index members. The list of objects is then sorted by these index members. When you add a new object to the list, the CObList derived class ensures that it is added in the correct position in the list.

Features of this code generator:

  • Produces CObject derived classes, and CObList derived classes to hold the objects in a sorted list
  • Class name follows the selected file name
  • Variables are assigned data types based on Hungarian notation prefixes
  • Includes Serialization code
  • All data members are protected and accessed with Get/Set inline functions
  • Includes initialization code in constructor
  • Includes member function to duplicate the properties of an object
  • Includes last modified date/time
  • Includes Dump and AssertValid functions
  • Object list can be sorted on multiple fields
Limitations of the current version:
  • Currently, you can only create one "key" value, although with a little trickery, your could run the application multiple times to generate multiple CObList derived class and allow multiple lists.
  • If you change the value of one of the key fields, the list does not resort. Although it would be a simple matter to add a sort function to the CObList derived class, the difficult is that there could be multiple instances of the CObList derived class throughout your application, all containing pointers to the same objects. So if one object changed a key field, you have to resort all those lists. The question is how best to keep track of where all those lists are. I don't have an answer for that yet!
  • The function to add a new object to the list is not well optimized for the sorted list
  • There is no copy constructor

To use the code generator:

1. Select a file name for the source file output. Your header file will have the same name but with an ".h" extension. Also, the class name is derived from the file name such that Example.cpp will produce a class called "CExample", and the COblist derived class will be CExampleList. Note that the code generator will overwrite any existing files.

2. Enter the names of the data members for the class. Data types are determined from the Hungarian notation prefixes. The program uses the following prefixes (these are easy to change):

  • dt -- COleDateTime
  • str -- CStirng
  • n -- int
  • f -- double (not FLAG!)
  • b -- BOOL
  • rgb -- COLORREF
If you want to generate a CObList derived class to hold your objects, enter Index members for the class. These will be added to your CObject derived class. The list will be sorted by these members in the order in which they appear. The indeces will also be used for comparing objects, and will available as parameters in a constructor.

If you leave the Indeces list blank, the application will not generate a CObList derived class. Only the CObject derived class will be generated.

3. Click the "Generate" button to generate the source file and header file.

The code generator produces code using my own programming style so you may want to adapt it to more closely follow your own style.

Here is the header file code generated using the program as configured in the above picture:



///////////////////////////////////////////////////////////////////////////
// CExample -- Interface for CExample object



#ifndef __EXAMPLE_H__
#define __EXAMPLE_H__


class CExample;

// This ObList derived class is generated if you add index member functions

class CExampleList : public CObList
{
public:
	CExample* FindEntry(COleDateTime dtDate, int nOrder, CString strLocationID);
	POSITION FindEntryPos(COleDateTime dtDate, int nOrder, CString strLocationID);
	POSITION FindEntryPosBruteForce(COleDateTime dtDate, int nOrder, CString strLocationID);
	void AddExample(CExample* pNew);
	void RemoveExample(COleDateTime dtDate, int nOrder, CString strLocationID);
	virtual void Serialize(CArchive& ar);
	void ClearAndDelete();
};


// Here is the CObject derived class

class CExample : public CObject
{
// construction
public:
	DECLARE_SERIAL(CExample);
	CExample();
	CExample(COleDateTime dtDate, int nOrder, CString strLocationID);
	~CExample();

// Attributes
public:



protected:
	COleDateTime m_dtDate;
	int m_nOrder;
	CString m_strLocationID;
	CString m_strCustomerName;
	COleDateTime m_dtBirthDate;
	COLORREF m_rgbColor;
	COleDateTime m_dtCreated;
	COleDateTime m_dtLastModified;


// Operations
public:
	virtual void Serialize(CArchive& ar);
	void Duplicate(CExample* pSource);
	void Clear();
	int Compare(COleDateTime dtDate, int nOrder, CString strLocationID);
	int Compare(CExample* pTest);


// Diagnostics
#ifdef _DEBUG
	void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif


// inlines
public:
	inline void SetDate(COleDateTime dtNew) {
		m_dtLastModified = COleDateTime::GetCurrentTime();
		m_dtDate = dtNew; }
	inline COleDateTime GetDate() {;
		return m_dtDate; }

	inline void SetOrder(int nNew) {
		m_dtLastModified = COleDateTime::GetCurrentTime();
		m_nOrder = nNew; }
	inline int GetOrder() {;
		return m_nOrder; }

	inline void SetLocationID(CString strNew) {
		m_dtLastModified = COleDateTime::GetCurrentTime();
		m_strLocationID = strNew;
		m_strLocationID.FreeExtra(); }
	inline CString GetLocationID() {;
		return m_strLocationID; }

	inline void SetCustomerName(CString strNew) {
		m_dtLastModified = COleDateTime::GetCurrentTime();
		m_strCustomerName = strNew;
		m_strCustomerName.FreeExtra(); }
	inline CString GetCustomerName() {;
		return m_strCustomerName; }

	inline void SetBirthDate(COleDateTime dtNew) {
		m_dtLastModified = COleDateTime::GetCurrentTime();
		m_dtBirthDate = dtNew; }
	inline COleDateTime GetBirthDate() {;
		return m_dtBirthDate; }

	inline void SetColor(COLORREF rgbNew) {
		m_dtLastModified = COleDateTime::GetCurrentTime();
		m_rgbColor = rgbNew; }
	inline COLORREF GetColor() {;
		return m_rgbColor; }

	inline void SetCreated(COleDateTime dtNew) {
		m_dtLastModified = COleDateTime::GetCurrentTime();
		m_dtCreated = dtNew; }
	inline COleDateTime GetCreated() {;
		return m_dtCreated; }

	inline void SetLastModified(COleDateTime dtNew) {
		m_dtLastModified = COleDateTime::GetCurrentTime();
		m_dtLastModified = dtNew; }
	inline COleDateTime GetLastModified() {;
		return m_dtLastModified; }



};


#endif // #define __EXAMPLE_H__



Here is the source file code generated using the program as configured in the above picture. The green comments are ones I added for this article and are not generated by the program.


///////////////////////////////////////////////////////////////////////////
// CExample -- Implementation for CExample object


#include "stdafx.h"
#include "Example.h"

IMPLEMENT_SERIAL(CExample, CObject, 0);


////////////////////////////////////////////////////////////
// CExampleList class members

// This function finds an object based on the index values provided
// it returns a pointer to the object
CExample* CExampleList::FindEntry(COleDateTime dtDate, int nOrder, CString strLocationID)
{
	POSITION Pos = FindEntryPos(dtDate, nOrder, strLocationID);
	if (Pos == NULL) return NULL;
	return (CExample*)GetAt(Pos);
}


// This function finds the POSITION of an object based on the
// key values provided
POSITION CExampleList::FindEntryPos(COleDateTime dtDate, int nOrder, CString strLocationID)
{
	POSITION Pos;
	CExample* pExample;
	div_t divresult;

	int nCurrent, nHigh, nLow, nCompareResult, nLastCurrent = -1;
	nLow = 0;
	nHigh = GetCount();
	divresult = div(nHigh - nLow, 2);
	nCurrent = nLow + divresult.quot;

	if (nHigh <= 0) goto l_NotFound;  // no items in the list
	while (TRUE)
	{
		Pos = FindIndex(nCurrent);
		pExample = (CExample*)GetAt(Pos);
		nCompareResult = pExample->Compare(dtDate, nOrder, strLocationID);
		if (nCompareResult == 0)
		{
			return Pos;
		}
		if (nCompareResult > 0) // we are in lower half of test range
		{
			nHigh = nCurrent;
		divresult = div(nHigh - nLow, 2);
		nCurrent = nLow + divresult.quot;
		}
		else // we are in upper half of test range
		{
			nLow = nCurrent;
		divresult = div(nHigh - nLow, 2);
		nCurrent = nLow + divresult.quot;
		}
		if (nCurrent == nLastCurrent) goto l_NotFound;
		nLastCurrent = nCurrent;
	}

	l_NotFound:;

// The search above is optimized to work on a pre-sorted list
// To make sure it works, we search the list through brute force.  If we didn't
// find it above, we shouldn't find it below

#ifdef _DEBUG
	Pos = FindEntryPosBruteForce(dtDate, nOrder, strLocationID);
	if (Pos != NULL) TRACE("Searching algorithm failed\n");
#endif

	return NULL;
} // end of FindEntryPos


// This function searches the list for an object
// based on the key values provided.  However it does not require
// a pre-sorted list.  You should implement this class so that this function
// is not required in the release version

POSITION CExampleList::FindEntryPosBruteForce(COleDateTime dtDate, int nOrder, CString strLocationID)
{
	CExample* pExample;
	POSITION Pos = GetHeadPosition();
	while (Pos)
	{
		pExample = (CExample*)GetNext(Pos);
		if (pExample->Compare(dtDate, nOrder, strLocationID) == 0)
		{
			return Pos;
		}
	}
	return NULL;
} // end of FindEntryPosBruteForce


// This function adds an object to the list and places it in
// it's proper position based on the value of the key fields

void CExampleList::AddExample(CExample* pNew)
{
	CExample* pExample;
	int nCompareResult;
	POSITION Pos;

	// need to search through list and add in the proper sorted order
	ASSERT_VALID(pNew);
	ASSERT(Find(pNew) == NULL);

	// start from end because it is more likely to be added to the end
	Pos = GetTailPosition();
	while (Pos)
	{
		pExample = (CExample*)GetAt(Pos);
		nCompareResult = pExample->Compare(pNew);
		ASSERT(nCompareResult != 0);
		if (nCompareResult == 0) return;
		if (nCompareResult == -1)
		{
			InsertAfter(Pos, pNew);
			return;
		}
		GetPrev(Pos);
	}
	AddHead(pNew);
	return;
}


void CExampleList::RemoveExample(COleDateTime dtDate, int nOrder, CString strLocationID)
{
	POSITION Pos = FindEntryPos(dtDate, nOrder, strLocationID);
	if (Pos) RemoveAt(Pos);
}


// Function to serialize the list and all it's objects

void CExampleList::Serialize(CArchive& ar)
{
	// NOTE:  Do not call the base class!
	DWORD dwVersion = 0x00000000;
	int n, nCount;
	POSITION Pos;
	CExample* pExample;

	if (ar.IsStoring())
	{
		ar<Serialize(ar);
		}
	}
	else
	{
		ar>>dwVersion;
		ASSERT(GetCount() == 0);
		ar>>nCount;
		for (n = 0; n < nCount; ++n)
		{
			pExample = new CExample();
			if (pExample == NULL)
			THROW(new CMemoryException());
			pExample->Serialize(ar);
			AddTail(pExample);
		}
	}
} // end of Serialize

// This function clears the list but also deletes the object.
// Make sure you only delete the objects once!
// If you have multiple instances of this list, only one should ever call this function!
void CExampleList::ClearAndDelete()
{
	CExample* pExample;
	POSITION Pos = GetHeadPosition();
	while (Pos)
	{
		pExample = (CExample*)GetNext(Pos);
		ASSERT_VALID(pExample);
		delete pExample;
	}
	RemoveAll();
}



////////////////////////////////////////////////////////////
// CExample class members



////////////////////////////////////////////
// CExample construction/destruction 


// Construction
CExample::CExample()
{
	Clear();
	m_dtCreated = COleDateTime::GetCurrentTime();
}

// If you create Index fields for your object,
// the application will generate a second constructor with the index fields as parameters

CExample::CExample(COleDateTime dtDate, int nOrder, CString strLocationID)
{
	Clear();
	m_dtCreated = COleDateTime::GetCurrentTime();
	m_dtDate = dtDate;
	m_nOrder = nOrder;
	m_strLocationID = strLocationID;
}


// Initialization
void CExample::Clear()
{
	m_dtDate = 0.0;
	m_nOrder = 0;
	m_strLocationID = _T("");
	m_strCustomerName = _T("");
	m_dtBirthDate = 0.0;
	m_rgbColor = 0;
	m_dtCreated = 0.0;
	m_dtLastModified = 0.0;
}



// Destruction
CExample::~CExample()
{



}




////////////////////////////////////////////
// CExample Diagnostics 

#ifdef _DEBUG

void CExample::Dump(CDumpContext& dc) const
{
	dc.SetDepth(1);
	dc <<"Date = " << m_dtDate;
	dc <<"Order = " << m_nOrder;
	dc <<"LocationID = " << m_strLocationID;
	dc <<"CustomerName = " << m_strCustomerName;
	dc <<"BirthDate = " << m_dtBirthDate;
	dc <<"Color = " << m_rgbColor;
	dc <<"Created = " << m_dtCreated;
	dc <<"LastModified = " << m_dtLastModified;
}

void CExample::AssertValid() const
{
	CObject::AssertValid();

	// TODO:  Add validity checking here
}
#endif





////////////////////////////////////////////
// CExample operations 


void CExample::Serialize(CArchive& ar)
{
	DWORD dwVersion = 0x00000000;

	if (ar.IsStoring())
	{
		ar<>dwVersion;
		ar>>m_dtDate>>m_nOrder>>m_strLocationID>>m_strCustomerName>>m_dtBirthDate>>m_rgbColor>>m_dtCreated>>m_dtLastModified;


	}
	CObject::Serialize(ar);
} // end of Serialize


// I prefer a duplicate function rather than a copy constructor

void CExample::Duplicate(CExample* pSource)
{
	m_dtDate = pSource->m_dtDate;
	m_nOrder = pSource->m_nOrder;
	m_strLocationID = pSource->m_strLocationID;
	m_strCustomerName = pSource->m_strCustomerName;
	m_dtBirthDate = pSource->m_dtBirthDate;
	m_rgbColor = pSource->m_rgbColor;
	m_dtCreated = pSource->m_dtCreated;
	m_dtLastModified = pSource->m_dtLastModified;
} // end of Duplicate


// To support the searching and sorting in the list
// we must have a compare function to compare to objects based on their key fields
// the function operates the same as CString::Compare
int CExample::Compare(COleDateTime dtDate, int nOrder, CString strLocationID)
{
	int nCompare;

	if (dtDate.m_status != COleDateTime::valid) return -1;
	if (m_dtDate < dtDate) return -1;
	if (m_dtDate > dtDate) return 1;

	if (m_nOrder < nOrder) return -1;
	if (m_nOrder > nOrder) return 1;

	nCompare = m_strLocationID.Compare(strLocationID);
	if (nCompare < 0) return -1;
	if (nCompare > 0) return 1;

	return 0;
}

int CExample::Compare(CExample* pTest)
{
	return Compare(pTest->GetDate(), pTest->GetOrder(), pTest->GetLocationID());
}




So that's it. I am somewhat new to OODB, so I am interested in feedback and improvements.

Download demo project - 149 KB

Date Last Updated: April 16, 1999



Comments

  • connecting to MSSQL from c++ program

    Posted by geeta_tr on 12/02/2005 04:23am

    ho wto connect to MSSQL from c++ desktop app. mail to geeta_tr@yahoo.com

    Reply
  • how to connect VC++ and MS Access

    Posted by Legacy on 05/23/2003 12:00am

    Originally posted by: R.Thamizhmaran

    please tell how to connect any database with vc++ to store and retrieve CAD data...
    
    


    Reply
  • how can i connect oracle with C

    Posted by Legacy on 02/26/2003 12:00am

    Originally posted by: DEBASHIS

    plz reply.

    Reply
  • database

    Posted by Legacy on 02/05/2003 12:00am

    Originally posted by: srinu

    method to connect databases using 'c'

    Reply
  • database handling with 'c'

    Posted by Legacy on 08/06/2002 12:00am

    Originally posted by: shyam

    hi,
    I want to learn database like MSAccess and Oracle handiling using 'c'. If any one know about it or can tell me where i can find about them, kindly inform me.
    regards
    shyam.s

    • Db handling in c/c++

      Posted by sujoy_acharya on 06/08/2004 04:59am

      http://www.hk8.org/old_web/linux/sql/ go to this site. Chapter 13
      if u get anything cOoL then mail me
      sujoy_acharya@sify.com

      Reply
    Reply
  • Great

    Posted by Legacy on 06/04/2002 12:00am

    Originally posted by: venkatesh


    Great! I've successfully used this utility many times. Thanx a lot.
    and i need help to create data base with help of borland c++
    builder(mfc) can u help me

    Reply
  • is it db-library?

    Posted by Legacy on 05/08/2001 12:00am

    Originally posted by: M. Ashok Kumar

    I am a fresher in C++ . I had gone thru your coding and was not able to understand anthing. Can U help me about this. Like what for this program is ?


    And I want to know about the db-library connectivity in C++.
    Can U help me regarding this ?


    Thanking You

    Ashok

    Reply
  • Thanks highly recommonded & Useful effort

    Posted by Legacy on 04/11/2001 12:00am

    Originally posted by: Trigunait O.P.

    Thanks for your individual and group effort for this projects.

    This project is highly appreciated by the students of MCA Final in IGNOU university.

    Thanks.

    Reply
  • New version

    Posted by Legacy on 11/18/2000 12:00am

    Originally posted by: jack zhang

    AppBuilder--A complete truly visual C/C++ IDE.it offers Microsoft Foundation Class developers a complete library of MFC extension classes that implement Authentic Looking GUIs like those seen in Microsoft money 2000? AppBuilder can help developers develop application with database.The classes fit seamlessly with MFC and inherit many of MFC's existing classes. You can now easily give your database application the MS money look, without going broke! that's not all,AppBuilder is also a code generater,it can generate database code based on ODBC API or MFC ODBC, this can help you develop manage information system easily and quickly. If you want to learn more about appbuilder,Please visit: http://www.ucancode.net

    Reply
  • Great!

    Posted by Legacy on 02/23/2000 12:00am

    Originally posted by: Dmitry

    Great! I've successfully used this utility many times. Thanx a lot.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: September 19, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT In response to the rising number of data breaches and the regulatory and legal impact that can occur as a result of these incidents, leading analysts at Forrester Research have developed five important design principles that will help security professionals reduce their attack surface and mitigate vulnerabilities. Check out this upcoming eSeminar and join Chris Sherman of Forrester Research to learn how to deal with the influx of new device …

  • Specialization and efficiency are always in need. Whether it's replacing an aging roof, getting a haircut, or tuning up a car, most seek the assistance of trusted experts. The same is true in the business world, where an increasing number of companies are seeking the help of others to administer their IT systems and services. This special edition of Unleashing IT highlights a new breed of IT caretaker -- Cisco Powered service providers -- and the business advantages and operational efficiencies they …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds