- Table of Contents
- Copyright
- About the Authors
- About the Contributors
- Acknowledgments
- Tell Us What You Think!
- Introduction
- How to Use This Book
- What You Need to Use This Book
- What's New in Visual C++ 6.0
- Contacting the Main Author
- Part I: Introduction
- Chapter 1. The Visual C++ 6.0 Environment
- Part II: MFC Programming
- Chapter 2. MFC Class Library Overview
- Chapter 3. MFC Message Handling Mechanism
- Chapter 4. The Document View Architecture
- Chapter 5. Creating and Using Dialog Boxes
- Chapter 6. Working with Device Contexts and GDI Objects
- Chapter 7. Creating and Using Property Sheets
- Chapter 8. Working with the File System
- Chapter 9. Using Serialization with File and Archive Objects
- Part III: Internet Programming with MFC
- Chapter 10. MFC and the Internet Server API (ISAPI)
- Chapter 11. The WinInet API
- Chapter 12. MFC HTML Support
- Part IV: Advanced Programming Topics
- Chapter 13. Using the Standard C++ Library
- Chapter 14. Error Detection and Exception Handling Techniques
- Chapter 15. Debugging and Profiling Strategies
- Chapter 16. Multithreading
- Chapter 17. Using Scripting and Other Tools to Automate the Visual C++ IDE
- Part V: Database Programming
- Chapter 18. Creating Custom AppWizards
- Chapter 19. Database Overview
- Chapter 20. ODBC Programming
- Chapter 21. MFC Database Classes
- Chapter 22. Using OLE DB
- Chapter 23. Programming with ADO
- Part VI: MFC Support for COM and ActiveX
- Chapter 24. Overview of COM and Active Technologies
- Chapter 25. Active Documents
- Chapter 26. Active Containers
- Chapter 27. Active Servers
- Chapter 28. ActiveX Controls
- Part VII: Using the Active Template Library
- Chapter 29. ATL Architecture
- Chapter 30. Creating COM Objects Using ATL
- Chapter 31. Creating ActiveX Controls Using ATL
- Chapter 32. Using ATL to Create MTS and COM+ Components
- Part VIII: Finishing Touches
- Chapter 33. Adding Windows Help
- Part IX: Appendix
The CDatabase Class
The MFC CDatabase class is used to encapsulate your application's dealings with a connection to the database. This may be a connection to a database server over the network, or it may just be used to keep track of your settings for a desktop database on the local machine. In most cases, the methods associated with CDatabase correspond directly to the functions of the ODBC C API that work with connection handles.
You can retrieve the CDatabase class associated with your CRecordset class by using the m_pSet->m_pDatabase CRecordset class variable.
Executing SQL Statements with CDatabase
For general queries that return resultsets, it usually is easier to use the CRecordset class, which you will look at next. However, you can execute SQL statements that do not return resultsets without using a CRecordset. You do this by calling CDatabase::ExecuteSQL(),:
void ExecuteSQL( LPCSTR lpszSQL );
This function simply takes a SQL string passed in lpszSQL and executes it against the current datasource. Notice that ExecuteSQL() does not return a value. If something goes wrong (for example, the SQL statement fails), a CDBException is thrown. Your application needs to catch these in order to determine whether the statement did not execute properly.
OnSetOptions()
When you call ExecuteSQL(), the MFC framework makes a call to the OnSetOptions() member of CDatabase before it sends the SQL statement to the database. This allows the CDatabase object to set up any options that are required before executing SQL statements.
In the default implementation, this function simply sets the SQL_QUERY_TIMEOUT option for the statement handle that will be used for the operation to the value that was specified with a call to CDatabase::SetQueryTimeout(). You can add any other options you may need by deriving your own class from CDatabase and overriding the OnSetOptions() member function, which is passed the statement handle that MFC will use to execute the statement.
Transactions with CDatabase
The CDatabase class also is responsible for managing transactions for the database connection. Transactions enable you to execute a series of SQL statements as a single operation. If one of the operations in a transaction fails, the rest of the operations in the transaction also can be undone.
This feature is most useful when you need to make several different, but related, changes to a database. If you are entering a sales order, for example, you may want to update both your Shipping table and your Billing table. If you update one of these and the other update fails, you can expect a few extra customer service calls.
To begin a transaction using the MFC ODBC classes, call CDatabase::BeginTrans(). You then can execute the operations that make up the transaction by calling CDatabase::ExecuteSQL() or by using CRecordset objects derived from this CDatabase.
A transaction can end in one of two ways. If all of the operations were successful and you want to go through with the transaction, you should call CDatabase::CommitTrans(). If an error has occurred, and you want to cancel the transaction, you should call CDatabase::Rollback(), which will undo all the operations performed with this CDatabase (and any derived recordsets) since the call to BeginTrans().
This example shows a simple transaction involving a row insertion made by calling ExecuteSQL():
try {
m_pSet->m_pDatabase->BeginTrans();
m_pSet->m_pDatabase->ExecuteSQL(
"INSERT INTO Employee VALUES ('Joe Beancounter', 'Accounting', 80000)");
m_pSet->m_pDatabase->CommitTrans())
TRACE("Transaction Commited\n");
else
TRACE("Error in CommitTrans\n");
}
catch(CDBException *pEx) {
pEx->ReportError();
m_pSet->m_pDatabase->Rollback();
}
Effects of Transactions on CRecordsets
Ending a transaction on a CDatabase object can have different effects on the CRecordsets that are created from it, depending on the ODBC driver that you are using. Calling CRecordset::GetCursorCommitBehavior() and CDatabase::RollbackBehavior() en ables you to find out how your driver affects CRecordsets when you call CommitTrans() or Rollback(). Both of these functions will return one of the following values:
- SQL_CB_CLOSE—The cursors for any CRecordsets are closed. If you want to use them after completing a transaction, call CRecordset::Requery().
- SQL_CB_DELETE—Any cursors for CRecordsets associated with this CDatabase are deleted. You should call CRecordset::Close() and reopen the CRecordset if you need to use it again.
- SQL_CB_PRESERVE—The CRecordsets built from this CDatabase are not affected, and your app can continue to use them in their current state.
Using the ODBC API Directly
For some applications, the MFC database classes may not give you quite enough control over the database interaction. If you need to do anything not directly supported by the MFC classes, you can call the ODBC C API directly. Of course, to call the ODBC API, you need ODBC handles. Well, it just so happens that you can get the ODBC connection handle from the m_hdbc member of CDatabase. You also can get statement handles from the m_hstmt member of the CRecordset class.
You may freely mix ODBC C API calls with use of the MFC database classes in your applications. However, you may want to take a look at the source code for the MFC classes to see how the MFC member functions use the ODBC API.
Exception Handling | Next Section

Account Sign In
View your cart