Download Classes para Manipulação de BDs 5

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts

Database wikipedia , lookup

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

Open Database Connectivity wikipedia , lookup

Database model 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