After the connection is made, the first record from the Employees table is displayed on the Employee form. Reading data and displaying the results on the form occur in the view portion of the code. The application updates the view whenever the position in the recordset is changed in response to one of the four commands available from the toolbar or Edit menu. Each command invokes a related function within the document. (Because the recordset contains the data, it is associated with the document and not the view.) For example, clicking the Next command calls the OnEditNext function:
void CDAOEMPDoc::OnEditNext() { if(!OKToMove()) return; m_cEmpRecordSet.MoveNext(); //Watch for end of recordset. if(m_cEmpRecordSet.GetEOF()) { MessageBeep(0); m_cEmpRecordSet.MovePrevious(); } else { UpdateAllViews(NULL); } }
The OnEditNext function first calls the OKToMove function, which checks to see if the recordset is empty or if the record has been updated. (Record updates are discussed in “Updating Records from the Employee Database” later in this chapter.) The MoveNext method then positions the recordset to the next record. The end-of-file condition is checked. If it occurs, the application moves back to the previous record; otherwise, the view is updated. If the end of the recordset is reached, there is no need to update the view, and the application moves back to the last record displayed.
In terms of actually reading data, the application calls the OnUpdate member function to update the form view’s appearance:
void CDAOEMPView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) { CDAOEMPDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (pDoc->m_bEmptyTable) return; try { m_nEmpNum = VTOLONG(pDoc->m_cEmpRecordSet.Fields[EMP_EMPLOYEE_ID].GetValue()); //Convert the variant strings into Cstrings. VarToCStr(&m_strFirstName, &pDoc->m_cEmpRecordSet.Fields[EMP_FIRST_NAME].GetValue()); VarToCStr(&m_strHomePhone, &pDoc->m_cEmpRecordSet.Fields[EMP_HOME_PHONE].GetValue()); VarToCStr(&m_strLastName, &pDoc->m_cEmpRecordSet.Fields[EMP_LAST_NAME].GetValue()); VarToCStr(&m_strNotes, &pDoc->m_cEmpRecordSet.Fields[EMP_NOTES].GetValue()); //ColeDateTime: m_HireDate = pDoc->m_cEmpRecordSet.Fields[EMP_HIRE_DATE].GetValue(); } catch (CdbException dbExcept) { CdbLastOLEError exError; TCHAR szBuf[256]; //If error is "No Current Record," assume empty table and clear members. if(dbExcept.m_hr == E_DAO_NoCurrentRecord) { pDoc->m_bEmptyTable = TRUE; m_nEmpNum = 0; m_strFirstName = ""; m_strHomePhone = ""; m_strLastName = ""; m_strNotes = ""; m_HireDate = COleDateTime(1990,1,1,0,0,0); } else { wsprintf(szBuf, _T("Error %d : %s\n"), DBERR(dbExcept.m_hr), (LPCTSTR) exError.GetDescription()); AfxMessageBox(szBuf); return; } } UpdateData(FALSE); //Invoke Data Exchange (copy member data to form controls). Invalidate(); //Repaint. }
Data is returned as variants, so you must convert returned values to member variables’ data types. Daoemp.h defines several useful macros for handling data conversion, such as VTOLONG, which converts a variant to a LONG data type:
#define VTOLONG(v) ((v).vt==VT_I4 ? (LONG)(v).iVal:0L)
Note that this conversion converts a null value represented by VT_NULL into the long value 0L, which may not always be what you want.
Although not shown in the Employee application, the dbDAO GetRowsEx method provides an alternate method of reading data directly as native C data types. Although it involves writing more code, the GetRowsEx method improves performance because it bypasses this extra data conversion.
See Also For more information about the GetRowsEx method, see “Performing Bulk Fetches with GetRows and GetRowsEx” later in this chapter.
The final step is to update the form controls themselves by calling the UpdateData member function with an argument of FALSE. The UpdateData function uses DDX to maintain mappings between data of the CDAOEMPView class and the controls in the dialog box template resource for this form view.