* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Download Classes para Manipulação de BDs 5
Survey
Document related concepts
Entity–attribute–value model wikipedia , lookup
Relational model wikipedia , lookup
Microsoft Jet Database Engine wikipedia , lookup
Clusterpoint wikipedia , lookup
Functional Database Model wikipedia , lookup
Extensible Storage Engine wikipedia , lookup
Transcript
Classes para Manipulação de BDs 5 Ambientes de Desenvolvimento A Avançados Engenharia Informática Instituto Superior de Engenharia do Porto Alexandre Bragança 1998/99 Baseada em Documentos da Microsoft Ambientes de Desenvolvimento Avançados 5 Classes para Manipular BD através do ODBC Alexandre Bragança Pág 2 Ambientes de Desenvolvimento Avançados 5 Classes para Manipular BD através do ODBC • Grande parte das ferramentas de desenvolvimento 'esconde' a complexidade do ODBC implementando uma abstração superior para acesso a base de dados. • No Visual C++ a biblioteca de classes de 'eleição' é a biblioteca MFC (Microsoft Foundation Classes). • Esta biblioteca de classes contem diversas classes de apoio ao desenvolvimento de aplicações em ambiente Windows. Grande parte destas classes 'funciona' de forma bastante interligada com a própria ferramenta de desenvolvimento (Visual C++). • As MFC contêm classes para acesso a bases de dados através do ODBC. Alexandre Bragança Pág 3 Ambientes de Desenvolvimento Avançados ODBC Classes These classes work with the other application framework classes to give easy access to a wide variety of databases for which Open Database Connectivity (ODBC) drivers are available. Programs that use ODBC databases will have at least a CDatabase object and a CRecordset object. CDatabase Encapsulates a connection to a data source, through which you can operate on the data source. CRecordset Encapsulates a set of records selected from a data source. Recordsets enable scrolling from record to record, updating records (adding, editing, and deleting records), qualifying the selection with a filter, sorting the selection, and parameterizing the selection with information obtained or calculated at run time. CRecordView Provides a form view directly connected to a recordset object. The dialog data exchange (DDX) mechanism exchanges data between the recordset and the controls of the record view. Like all form views, a record view is based on a dialog template resource. Record views also support moving from record to record in the recordset, updating records, and closing the associated recordset when the record view closes. CDBException An exception resulting from failures in data access processing. This class serves the same purpose as other exception classes in the exception-handling mechanism of the class library. CFieldExchange Supplies context information to support record field exchange (RFX), which exchanges data between the field data members and parameter data members of a recordset object and the corresponding table columns on the data source. Analogous to class CDataExchange, which is used similarly for dialog data exchange (DDX). Related Classes CLongBinary Encapsulates a handle to storage for a binary large object (or BLOB), such as a bitmap. CLongBinary objects are used to manage large data objects stored in database tables. CDBVariant Allows you to store a value without worrying about the value’s data type. CDBVariant tracks the data type of the current value, which is stored in a union. Alexandre Bragança Pág 4 Ambientes de Desenvolvimento Avançados CDatabase A CDatabase object represents a connection to a data source, through which you can operate on the data source. A data source is a specific instance of data hosted by some database management system (DBMS). Examples include Microsoft SQL Server, Microsoft Access, Borland® dBASE®, and xBASE. You can have one or more CDatabase objects active at a time in your application. Note If you are working with the Data Access Objects (DAO) classes rather than the Open Database Connectivity (ODBC) classes, use class CDaoDatabase instead. For more information, see the articles Database Topics (General) and DAO and MFC. Both articles are in Visual C++ Programmer's Guide. To use CDatabase, construct a CDatabase object and call its OpenEx member function. This opens a connection. When you then construct CRecordset objects for operating on the connected data source, pass the recordset constructor a pointer to your CDatabase object. When you finish using the connection, call the Close member function and destroy the CDatabase object. Close closes any recordsets you have not closed previously. For more information about CDatabase, see the articles Data Source (ODBC) and Database Topics (General) in Visual C++ Programmer's Guide. #include <afxdb.h> Alexandre Bragança Pág 5 Ambientes de Desenvolvimento Avançados CDatabase Class Members Data Members m_hdbc Open Database Connectivity (ODBC) connection handle to a data source. Type HDBC. Construction CDatabase Open OpenEx Close Constructs a CDatabase object. You must initialize the object by calling OpenEx or Open. Establishes a connection to a data source (through an ODBC driver). Establishes a connection to a data source (through an ODBC driver). Closes the data source connection. Database Attributes GetConnect IsOpen GetDatabaseName CanUpdate CanTransact SetLoginTimeout SetQueryTimeout GetBookmarkPersistence GetCursorCommitBehavior GetCursorRollbackBehavior Alexandre Bragança Returns the ODBC connect string used to connect the CDatabase object to a data source. Returns nonzero if the CDatabase object is currently connected to a data source. Returns the name of the database currently in use. Returns nonzero if the CDatabase object is updatable (not read-only). Returns nonzero if the data source supports transactions. Sets the number of seconds after which a data source connection attempt will time out. Sets the number of seconds after which database query operations will time out. Affects all subsequent recordset Open, AddNew, Edit, and Delete calls. Identifies the operations through which bookmarks persist on recordset objects. Identifies the effect of committing a transaction on an open recordset object. Identifies the effect of rolling back a transaction on an open recordset object. Pág 6 Ambientes de Desenvolvimento Avançados Database Operations BeginTrans BindParameters CommitTrans Rollback Cancel ExecuteSQL Starts a “transaction” — a series of reversible calls to the AddNew, Edit, Delete, and Update member functions of class CRecordset — on the connected data source. The data source must support transactions for BeginTrans to have any effect. Allows you to bind parameters before calling CDatabase::ExecuteSQL. Completes a transaction begun by BeginTrans. Commands in the transaction that alter the data source are carried out. Reverses changes made during the current transaction. The data source returns to its previous state, as defined at the BeginTrans call, unaltered. Cancels an asynchronous operation or a process from a second thread. Executes an SQL statement. No data records are returned. Database Overridables Called by the framework to set standard connection options. The default implementation sets the query OnSetOptions timeout value. You can establish these options ahead of time by calling SetQueryTimeout. CDatabase Overview | Base Class Members | Hierarchy Chart Alexandre Bragança Pág 7 Ambientes de Desenvolvimento Avançados CRecordset A CRecordset object represents a set of records selected from a data source. Known as “recordsets,” CRecordset objects are typically used in two forms: dynasets and snapshots. A dynaset stays synchronized with data updates made by other users. A snapshot is a static view of the data. Each form represents a set of records fixed at the time the recordset is opened, but when you scroll to a record in a dynaset, it reflects changes subsequently made to the record, either by other users or by other recordsets in your application. Note If you are working with the Data Access Objects (DAO) classes rather than the Open Database Connectivity (ODBC) classes, use class CDaoRecordset instead. For more information, see the article Database Topics (General) and the article DAO and MFC. Both articles are in Visual C++ Programmer’s Guide. To work with either kind of recordset, you typically derive an application-specific recordset class from CRecordset. Recordsets select records from a data source, and you can then: • • • Scroll through the records. • • Sort the recordset. Update the records and specify a locking mode. Filter the recordset to constrain which records it selects from those available on the data source. Parameterize the recordset to customize its selection with information not known until run time. To use your class, open a database and construct a recordset object, passing the constructor a pointer to your CDatabase object. Then call the recordset’s Open member function, where you can specify whether the object is a dynaset or a snapshot. Calling Open selects data from the data source. After the recordset object is opened, use its member functions and data members to scroll through the records and operate on them. The operations available depend on whether the object is a dynaset or a snapshot, whether it is updatable or read-only (this depends on the capability of the Open Database Connectivity (ODBC) data source), and whether you have implemented bulk row fetching. To refresh records that may have been changed or added since the Open call, call the object’s Requery member function. Call the object’s Close member function and destroy the object when you finish with it. In a derived CRecordset class, record field exchange (RFX) or bulk record field exchange (Bulk RFX) is used to support reading and updating of record fields. For more information about recordsets and record field exchange, see the articles Database Topics (General), Recordset (ODBC), Recordset: Fetching Records in Bulk (ODBC), and Record Field Exchange. For a focus on dynasets and snapshots, see the articles Dynaset and Snapshot. All articles are in Visual C++ Programmer’s Guide. #include <afxdb.h> Alexandre Bragança Pág 8 Ambientes de Desenvolvimento Avançados CRecordset Class Members Data Members m_hstmt m_nFields m_nParams m_pDatabase m_strFilter m_strSort Contains the ODBC statement handle for the recordset. Type HSTMT. Contains the number of field data members in the recordset. Type UINT. Contains the number of parameter data members in the recordset. Type UINT. Contains a pointer to the CDatabase object through which the recordset is connected to a data source. Contains a CString that specifies a Structured Query Language (SQL) WHERE clause. Used as a filter to select only those records that meet certain criteria. Contains a CString that specifies an SQL ORDER BY clause. Used to control how the records are sorted. Construction CRecordset Open Close Constructs a CRecordset object. Your derived class must provide a constructor that calls this one. Opens the recordset by retrieving the table or performing the query that the recordset represents. Closes the recordset and the ODBC HSTMT associated with it. Recordset Attributes CanAppend CanBookmark CanRestart CanScroll CanTransact CanUpdate GetODBCFieldCount GetRecordCount GetStatus GetTableName GetSQL IsOpen IsBOF Alexandre Bragança Returns nonzero if new records can be added to the recordset via the AddNew member function. Returns nonzero if the recordset supports bookmarks. Returns nonzero if Requery can be called to run the recordset’s query again. Returns nonzero if you can scroll through the records. Returns nonzero if the data source supports transactions. Returns nonzero if the recordset can be updated (you can add, update, or delete records). Returns the number of fields in the recordset. Returns the number of records in the recordset. Gets the status of the recordset: the index of the current record and whether a final count of the records has been obtained. Gets the name of the table on which the recordset is based. Gets the SQL string used to select records for the recordset. Returns nonzero if Open has been called previously. Returns nonzero if the recordset has been positioned before the first record. There is no Pág 9 Ambientes de Desenvolvimento Avançados IsEOF IsDeleted current record. Returns nonzero if the recordset has been positioned after the last record. There is no current record. Returns nonzero if the recordset is positioned on a deleted record. Recordset Update Operations AddNew CancelUpdate Delete Edit Update Prepares for adding a new record. Call Update to complete the addition. Cancels any pending updates due to an AddNew or Edit operation. Deletes the current record from the recordset. You must explicitly scroll to another record after the deletion. Prepares for changes to the current record. Call Update to complete the edit. Completes an AddNew or Edit operation by saving the new or edited data on the data source. Recordset Navigation Operations GetBookmark Move MoveFirst MoveLast MoveNext MovePrev SetAbsolutePosition SetBookmark Assigns the bookmark value of a record to the parameter object. Positions the recordset to a specified number of records from the current record in either direction. Positions the current record on the first record in the recordset. Test for IsBOF first. Positions the current record on the last record or on the last rowset. Test for IsEOF first. Positions the current record on the next record or on the next rowset. Test for IsEOF first. Positions the current record on the previous record or on the previous rowset. Test for IsBOF first. Positions the recordset on the record corresponding to the specified record number. Positions the recordset on the record specified by the bookmark. Other Recordset Operations Cancel FlushResultSet GetFieldValue GetODBCFieldInfo GetRowsetSize GetRowsFetched GetRowStatus IsFieldDirty Alexandre Bragança Cancels an asynchronous operation or a process from a second thread. Returns nonzero if there is another result set to be retrieved, when using a predefined query. Returns the value of a field in a recordset. Returns specific kinds of information about the fields in a recordset. Returns the number of records you wish to retrieve during a single fetch. Returns the actual number of rows retrieved during a fetch. Returns the status of the row after a fetch. Returns nonzero if the specified field in the current Pág 10 Ambientes de Desenvolvimento Avançados IsFieldNull IsFieldNullable RefreshRowset Requery SetFieldDirty SetFieldNull SetLockingMode SetParamNull SetRowsetCursorPosition record has been changed. Returns nonzero if the specified field in the current record is Null (has no value). Returns nonzero if the specified field in the current record can be set to Null (having no value). Refreshes the data and status of the specified row(s). Runs the recordset’s query again to refresh the selected records. Marks the specified field in the current record as changed. Sets the value of the specified field in the current record to Null (having no value). Sets the locking mode to “optimistic” locking (the default) or “pessimistic” locking. Determines how records are locked for updates. Sets the specified parameter to Null (having no value). Positions the cursor on the specified row within the rowset. Recordset Overridables Check CheckRowsetError DoBulkFieldExchange DoFieldExchange GetDefaultConnect GetDefaultSQL OnSetOptions SetRowsetSize Alexandre Bragança Called to examine the return code from an ODBC API function. Called to handle errors generated during record fetching. Called to exchange bulk rows of data from the data source to the recordset. Implements bulk record field exchange (Bulk RFX). Called to exchange data (in both directions) between the field data members of the recordset and the corresponding record on the data source. Implements record field exchange (RFX). Called to get the default connect string. Called to get the default SQL string to execute. Called to set options for the specified ODBC statement. Specifies the number of records you wish to retrieve during a fetch. Pág 11 Ambientes de Desenvolvimento Avançados Example // Embed a CDatabase object // in your document class CDatabase m_dbCust; // Connect the object to a // data source (no password) // the ODBC connection dialog box // will always remain hidden m_dbCust.Open( _T( "MYDATASOURCE" ), FALSE, FALSE, _T( "ODBC;UID=JOES" ), // ...Or, query the user for all // connection information m_dbCust.Open( NULL ); Example // Embed a CDatabase object // in your document class CDatabase m_dbCust; // Connect the object to a // read-only data source where // the ODBC connection dialog box // will always remain hidden m_dbCust.OpenEx( _T( "DSN=MYDATASOURCE;UID=JOES" ), CDatabase::openReadOnly | CDatabase::noOdbcDialog ); Example CString strCmd = "UPDATE Taxes SET Federal = 36%"; TRY { m_dbCust.ExecuteSQL( strCmd ); } CATCH(CDBException, e) { // The error code is in e->m_nRetCode } END_CATCH Alexandre Bragança Pág 12 Ambientes de Desenvolvimento Avançados Example The following sample code illustrates calls to GetFieldValue for a recordset object declared directly from CRecordset. // Create and open a database object; // do not load the cursor library CDatabase db; db.OpenEx( NULL, CDatabase::forceOdbcDialog ); // Create and open a recordset object // directly from CRecordset. Note that a // table must exist in a connected database. // Use forwardOnly type recordset for best // performance, since only MoveNext is required CRecordset rs( &db ); rs.Open( CRecordset::forwardOnly, _T( "SELECT * FROM SomeTable" ) ); // Create a CDBVariant object to // store field data CDBVariant varValue; // Loop through the recordset, // using GetFieldValue and // GetODBCFieldCount to retrieve // data in all columns short nFields = rs.GetODBCFieldCount( ); while( !rs.IsEOF( ) ) { for( short index = 0; index < nFields; index++ ) { rs.GetFieldValue( index, varValue ); // do something with varValue } rs.MoveNext( ); } rs.Close( ); db.Close( ); Example This example rebuilds a recordset to apply a different sort order. // Example for CRecordset::Requery CCustSet rsCustSet( NULL ); // Open the recordset rsCustSet.Open( ); // Use the recordset ... // Set the sort order and Requery the recordset rsCustSet.m_strSort = "District, Last_Name"; if( !rsCustSet.CanRestart( ) ) return; // Unable to requery if( !rsCustSet.Requery( ) ) // Requery failed, so take action Alexandre Bragança Pág 13 Ambientes de Desenvolvimento Avançados Example This example shows a recordset created on the frame of a function. The example assumes the existence of m_dbCust, a member variable of type CDatabase already connected to the data source. // Create a derived CRecordset object CCustSet rsCustSet( &m_dbCust ); rsCustSet.Open( ); if( rsCustSet.IsEOF( ) || !rsCustSet.CanUpdate( ) || !rsCustSet.CanTransact( ) ) return; if( !m_dbCust.BeginTrans( ) ) { // Do something to handle a failure } else { // Perhaps scroll to a new record... // Delete the current record rsCustSet.Delete( ); // ... // Finished commands for this transaction if( <the user confirms the transaction> ) m_dbCust.CommitTrans( ); else // User changed mind m_dbCust.Rollback( ); } // ... Example // Example for CRecordset::Edit // To edit a record, // First set up the edit buffer rsCustSet.Edit( ); // Then edit field data members for the record rsCustSet.m_dwCustID = 2795; rsCustSet.m_strCustomer = "Jones Mfg"; // Finally, complete the operation if( !rsCustSet.Update( ) ) // Handle the failure to update Alexandre Bragança Pág 14 Ambientes de Desenvolvimento Avançados Example The following code assumes that COutParamRecordset is a CRecordsetderived object based on a predefined query with an input parameter and an output parameter, and having multiple result sets. Note the structure of the DoFieldExchange override. // // // // // // DoFieldExchange override Only necessary to handle parameter bindings. Don't use CRecordset-derived class with bound fields unless all result sets have same schema OR there is conditional binding code. void COutParamRecordset::DoFieldExchange( CFieldExchange* pFX ) { pFX->SetFieldType( CFieldExchange::outputParam ); RFX_Long( pFX, "Param1", m_nOutParamInstructorCount ); // The "Param1" name here is a dummy name // that is never used pFX->SetFieldType( CFieldExchange::inputParam ); RFX_Text( pFX, "Param2", m_strInParamName ); // The "Param2" name here is a dummy name // that is never used } // Now implement COurParamRecordset. // Assume db is an already open CDatabase object COutParamRecordset rs( &db ); rs.m_strInParamName = _T("Some_Input_Param_Value"); // Get the first result set // NOTE: SQL Server requires forwardOnly cursor // type for multiple rowset returning stored // procedures rs.Open( CRecordset::forwardOnly, "{? = CALL GetCourses( ? )}", CRecordset::readOnly); // Loop through all the data in the first result set while ( !rs.IsEOF( ) ) { CString strFieldValue; for( int nIndex = 0; nIndex < rs.GetODBCFieldCount( ); nIndex++ ) { rs.GetFieldValue( nIndex, strFieldValue ); // TO DO: Use field value string. } rs.MoveNext( ); } Alexandre Bragança Pág 15 Ambientes de Desenvolvimento Avançados // Retrieve other result sets... while( rs.FlushResultSet( ) ) { // must call MoveNext because cursor is invalid rs.MoveNext( ); while ( !rs.IsEOF( ) ) { CString strFieldValue; for( int nIndex = 0; nIndex < rs.GetODBCFieldCount( ); nIndex++ ) { rs.GetFieldValue( nIndex, strFieldValue ); // TO DO: Use field value string. } rs.MoveNext( ); } } // // // // // // All result sets have been flushed. Cannot use the cursor, but the output parameter, m_nOutParamInstructorCount, has now been written. Note that m_nOutParamInstructorCount not valid until CRecordset::FlushResultSet has returned FALSE, indicating no more result sets will be returned. // TO DO: Use m_nOutParamInstructorCount // Cleanup rs.Close( ); db.Close( ); Alexandre Bragança Pág 16