Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

C++ Object Oriented Database Generator

0.00/5 (No votes)
17 Nov 1999 1  
This project is a code generator to produce CObject-dervied data classes for Object-Oriented database management

Sample Image

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.


///////////////////////////////////////////////////////////////////////////

// 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<<dwVersion;

        nCount = GetCount();
        ar<<nCount;
        Pos = GetHeadPosition();
        while (Pos)
        {
            pExample = (CExample*)GetNext(Pos);
            pExample->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;


    }
    else
    {
        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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here