Home page | Introduction


ADDING A BUFFER

Current situation

When you want to access a table data, the Visual C++ 6.0 IDE lets you easily add to the project a new MFC class, derived from either CRecordset or CDaoRecordset. After having specified the data source and the concerned table, a class is automatically generated, which needs to specifically define a certain number of variables to be used for the communication with the database and a possible visualization window. Such communication is established through MFC specialized functions, which compel the new class to know the accessed fields type.

Introduced improvement

The classes CBufferRecSet and CBufferDaoRecSet, respectively derived from CRecordset and CDaoRecordset, have been planned to free from the quoted needs: these classes manage a dynamic buffer in order to automatically associate a variable to each recordset field, and besides contain methods to perform the data exchange between the Database and the buffer (DoFieldExchange) and between the buffer and a visualization window (DDX_FieldVariant), taking charge of calling the right MFC functions, according to the concerned field type. Furthermore, they provide methods to directly access the buffer variables, either in reading or in writing, and let you define a filter on the recordset during the Open call, passing as parameters the filtered field name and a pointer to a variable containing the referenced value (currently it's not allowed to filter more than one field). Their implementation keeps the compatibility with the MFC classes CRecordView and CDaoRecordView respectively.

Example

Let's see in the following listings an example of the simplification obtained using the classes CBufferRecSet and CBufferDaoRecSet instead of the original ones CRecordset and CDaoRecordset. On the left you can find the source code as the AppWizard has generated it, while on the right you can find the corresponding source code as modified in order to use the new classes. This is the meaning of the colours:

   modified source code    deleted source code    added source code

DAO

After having created a new MFC AppWizard (exe) project, with the options Single document and Database view with file support (choosing a DAO Data source accessing the table Orders in the Microsoft Access Database sample - Northwind.mdb), I have added to the generated dialog box as many edit boxes as fields in the table, and then, with the ClassWizard, I have connected the edit boxes with the variables associated to the fields.

class CDaoDBSet : public CDaoRecordset
{
public:
   CDaoDBSet(CDaoDatabase* pDatabase = NULL);
   DECLARE_DYNAMIC(CDaoDBSet)

// Field/Param Data
//{{AFX_FIELD(CDaoDBSet, CDaoRecordset)
   long m_OrderID;
   CString m_CustomerID;
   long m_EmployeeID;
   COleDateTime m_OrderDate;
   COleDateTime m_RequiredDate;
   COleDateTime m_ShippedDate;
   long m_ShipVia;
   COleCurrency m_Freight;
   CString m_ShipName;
   CString m_ShipAddress;
   CString m_ShipCity;
   CString m_ShipRegion;
   CString m_ShipPostalCode;
   CString m_ShipCountry;
//}}AFX_FIELD

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CDaoDBSet)
public:
   virtual CString GetDefaultDBName(); // REVIEW: Get a comment here
   virtual CString GetDefaultSQL(); // default SQL for Recordset
   virtual void DoFieldExchange(CDaoFieldExchange* pFX); // RFX support
//}}AFX_VIRTUAL

// Implementation
#ifdef _DEBUG
   virtual void AssertValid() const;
   virtual void Dump(CDumpContext& dc) const;
#endif
};
class CDaoDBSet : public CBufferDaoRecSet
{
public:
   CDaoDBSet(CDaoDatabase* pDatabase = NULL);
   DECLARE_DYNAMIC(CDaoDBSet)

// Field/Param Data
//{{AFX_FIELD(CDaoDBSet, CBufferDaoRecSet)
//}}AFX_FIELD

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CDaoDBSet)
public:
   virtual CString GetDefaultDBName(); // REVIEW: Get a comment here
   virtual CString GetDefaultSQL(); // default SQL for Recordset
//}}AFX_VIRTUAL

// Implementation
#ifdef _DEBUG
   virtual void AssertValid() const;
   virtual void Dump(CDumpContext& dc) const;
#endif
};
CDaoDBSet::CDaoDBSet(CDaoDatabase* pdb)
   : CDaoRecordset(pdb)
{
//{{AFX_FIELD_INIT(CDaoDBSet)
   m_OrderID = 0;
   m_CustomerID = _T("");
   m_EmployeeID = 0;
   m_OrderDate = (DATE)0;
   m_RequiredDate = (DATE)0;
   m_ShippedDate = (DATE)0;
   m_ShipVia = 0;
   m_ShipName = _T("");
   m_ShipAddress = _T("");
   m_ShipCity = _T("");
   m_ShipRegion = _T("");
   m_ShipPostalCode = _T("");
   m_ShipCountry = _T("");
   m_nFields = 14;
//}}AFX_FIELD_INIT
   m_nDefaultType = dbOpenDynaset;
}
CDaoDBSet::CDaoDBSet(CDaoDatabase* pdb)
   : CBufferDaoRecSet(pdb)
{
//{{AFX_FIELD_INIT(CDaoDBSet)
//}}AFX_FIELD_INIT
   m_nDefaultType = dbOpenDynaset;
}
void CDaoDBSet::DoFieldExchange(CDaoFieldExchange* pFX)
{
//{{AFX_FIELD_MAP(CDaoDBSet)
   pFX->SetFieldType(CDaoFieldExchange::outputColumn);
   DFX_Long(pFX, _T("[OrderID]"), m_OrderID);
   DFX_Text(pFX, _T("[CustomerID]"), m_CustomerID);
   DFX_Long(pFX, _T("[EmployeeID]"), m_EmployeeID);
   DFX_DateTime(pFX, _T("[OrderDate]"), m_OrderDate);
   DFX_DateTime(pFX, _T("[RequiredDate]"), m_RequiredDate);
   DFX_DateTime(pFX, _T("[ShippedDate]"), m_ShippedDate);
   DFX_Long(pFX, _T("[ShipVia]"), m_ShipVia);
   DFX_Currency(pFX, _T("[Freight]"), m_Freight);
   DFX_Text(pFX, _T("[ShipName]"), m_ShipName);
   DFX_Text(pFX, _T("[ShipAddress]"), m_ShipAddress);
   DFX_Text(pFX, _T("[ShipCity]"), m_ShipCity);
   DFX_Text(pFX, _T("[ShipRegion]"), m_ShipRegion);
   DFX_Text(pFX, _T("[ShipPostalCode]"), m_ShipPostalCode);
   DFX_Text(pFX, _T("[ShipCountry]"), m_ShipCountry);
//}}AFX_FIELD_MAP
}
 
void CDaoDBView::DoDataExchange(CDataExchange* pDX)
{
   CDaoRecordView::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CDaoDBView)
   DDX_FieldText(pDX, IDC_EDIT1, m_pSet->m_OrderID, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT2, m_pSet->m_CustomerID, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT3, m_pSet->m_EmployeeID, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT4, m_pSet->m_OrderDate, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT5, m_pSet->m_RequiredDate, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT6, m_pSet->m_ShippedDate, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT7, m_pSet->m_ShipVia, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT8, m_pSet->m_Freight, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT9, m_pSet->m_ShipName, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT10, m_pSet->m_ShipAddress, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT11, m_pSet->m_ShipCity, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT12, m_pSet->m_ShipRegion, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT13, m_pSet->m_ShipPostalCode, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT14, m_pSet->m_ShipCountry, m_pSet);
//}}AFX_DATA_MAP
}
void CDaoDBView::DoDataExchange(CDataExchange* pDX)
{
   CDaoRecordView::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CDaoDBView)
//}}AFX_DATA_MAP

   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT1, 0); // OrderID
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT2, 1); // CustomerID
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT3, 2); // EmployeeID
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT4, 3); // OrderDate
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT5, 4); // RequiredDate
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT6, 5); // ShippedDate
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT7, 6); // ShipVia
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT8, 7); // Freight
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT9, 8); // ShipName
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT10, 9); // ShipAddress
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT11, 10); // ShipCity
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT12, 11); // ShipRegion
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT13, 12); // ShipPostalCode
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT14, 13); // ShipCountry
}

ODBC

After having created a new MFC AppWizard (exe) project, with the options Single document and Database view with file support (choosing an ODBC Data source accessing the table Orders in the Microsoft Access Database sample - Northwind.mdb), I have added to the generated dialog box as many edit boxes as fields in the table, and then, with the ClassWizard, I have connected the edit boxes with the variables associated to the fields.

class CODBCDBSet : public CRecordset
{
public:
   CODBCDBSet(CDatabase* pDatabase = NULL);
   DECLARE_DYNAMIC(CODBCDBSet)

// Field/Param Data
//{{AFX_FIELD(CODBCDBSet, CRecordset)
   long m_OrderID;
   CString m_CustomerID;
   long m_EmployeeID;
   CTime m_OrderDate;
   CTime m_RequiredDate;
   CTime m_ShippedDate;
   long m_ShipVia;
   CString m_Freight;
   CString m_ShipName;
   CString m_ShipAddress;
   CString m_ShipCity;
   CString m_ShipRegion;
   CString m_ShipPostalCode;
   CString m_ShipCountry;
//}}AFX_FIELD

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CODBCDBSet)
public:
   virtual CString GetDefaultConnect(); // Default connection string
   virtual CString GetDefaultSQL(); // default SQL for Recordset
   virtual void DoFieldExchange(CFieldExchange* pFX); // RFX support
//}}AFX_VIRTUAL

// Implementation
#ifdef _DEBUG
   virtual void AssertValid() const;
   virtual void Dump(CDumpContext& dc) const;
#endif
};
class CODBCDBSet : public CBufferRecSet
{
public:
   CODBCDBSet(CDatabase* pDatabase = NULL);
   DECLARE_DYNAMIC(CODBCDBSet)

// Field/Param Data
//{{AFX_FIELD(CODBCDBSet, CBufferRecSet)
//}}AFX_FIELD

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CODBCDBSet)
public:
   virtual CString GetDefaultConnect(); // Default connection string
   virtual CString GetDefaultSQL(); // default SQL for Recordset
//}}AFX_VIRTUAL

// Implementation
#ifdef _DEBUG
   virtual void AssertValid() const;
   virtual void Dump(CDumpContext& dc) const;
#endif
};
CODBCDBSet::CODBCDBSet(CDatabase* pdb)
   : CRecordset(pdb)
{
//{{AFX_FIELD_INIT(CODBCDBSet)
   m_OrderID = 0;
   m_CustomerID = _T("");
   m_EmployeeID = 0;
   m_OrderDate = 0;
   m_RequiredDate = 0;
   m_ShippedDate = 0;
   m_ShipVia = 0;
   m_Freight = _T("");
   m_ShipName = _T("");
   m_ShipAddress = _T("");
   m_ShipCity = _T("");
   m_ShipRegion = _T("");
   m_ShipPostalCode = _T("");
   m_ShipCountry = _T("");
   m_nFields = 14;
//}}AFX_FIELD_INIT
   m_nDefaultType = snapshot;
}
CODBCDBSet::CODBCDBSet(CDatabase* pdb)
   : CBufferRecSet(pdb)
{
//{{AFX_FIELD_INIT(CODBCDBSet)
//}}AFX_FIELD_INIT
   m_nDefaultType = snapshot;
}
void CODBCDBSet::DoFieldExchange(CFieldExchange* pFX)
{
//{{AFX_FIELD_MAP(CODBCDBSet)
   pFX->SetFieldType(CFieldExchange::outputColumn);
   RFX_Long(pFX, _T("[OrderID]"), m_OrderID);
   RFX_Text(pFX, _T("[CustomerID]"), m_CustomerID);
   RFX_Long(pFX, _T("[EmployeeID]"), m_EmployeeID);
   RFX_Date(pFX, _T("[OrderDate]"), m_OrderDate);
   RFX_Date(pFX, _T("[RequiredDate]"), m_RequiredDate);
   RFX_Date(pFX, _T("[ShippedDate]"), m_ShippedDate);
   RFX_Long(pFX, _T("[ShipVia]"), m_ShipVia);
   RFX_Text(pFX, _T("[Freight]"), m_Freight);
   RFX_Text(pFX, _T("[ShipName]"), m_ShipName);
   RFX_Text(pFX, _T("[ShipAddress]"), m_ShipAddress);
   RFX_Text(pFX, _T("[ShipCity]"), m_ShipCity);
   RFX_Text(pFX, _T("[ShipRegion]"), m_ShipRegion);
   RFX_Text(pFX, _T("[ShipPostalCode]"), m_ShipPostalCode);
   RFX_Text(pFX, _T("[ShipCountry]"), m_ShipCountry);
//}}AFX_FIELD_MAP
}
 
void CODBCDBView::DoDataExchange(CDataExchange* pDX)
{
   CRecordView::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CODBCDBView)
   DDX_FieldText(pDX, IDC_EDIT1, m_pSet->m_OrderID, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT2, m_pSet->m_CustomerID, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT3, m_pSet->m_EmployeeID, m_pSet);

// it's not possible to add the following ones, because CTime type is not supported
// DDX_FieldText(pDX, IDC_EDIT4, m_pSet->m_OrderDate, m_pSet);
// DDX_FieldText(pDX, IDC_EDIT5, m_pSet->m_RequiredDate, m_pSet);
// DDX_FieldText(pDX, IDC_EDIT6, m_pSet->m_ShippedDate, m_pSet);

   DDX_FieldText(pDX, IDC_EDIT7, m_pSet->m_ShipVia, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT8, m_pSet->m_Freight, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT9, m_pSet->m_ShipName, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT10, m_pSet->m_ShipAddress, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT11, m_pSet->m_ShipCity, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT12, m_pSet->m_ShipRegion, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT13, m_pSet->m_ShipPostalCode, m_pSet);
   DDX_FieldText(pDX, IDC_EDIT14, m_pSet->m_ShipCountry, m_pSet);
//}}AFX_DATA_MAP
}
void CODBCDBView::DoDataExchange(CDataExchange* pDX)
{
   CRecordView::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CODBCDBView)
//}}AFX_DATA_MAP

   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT1, 0); // OrderID
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT2, 1); // CustomerID
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT3, 2); // EmployeeID
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT4, 3); // OrderDate
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT5, 4); // RequiredDate
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT6, 5); // ShippedDate
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT7, 6); // ShipVia
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT8, 7); // Freight
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT9, 8); // ShipName
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT10, 9); // ShipAddress
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT11, 10); // ShipCity
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT12, 11); // ShipRegion
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT13, 12); // ShipPostalCode
   m_pSet->DDX_FieldVariant(pDX, IDC_EDIT14, 13); // ShipCountry
}

Home page | Introduction

1