Partager via


Record Field Exchange: How RFX Works

 

The new home for Visual Studio documentation is Visual Studio 2017 Documentation on docs.microsoft.com.

The latest version of this topic can be found at Record Field Exchange: How RFX Works.

This topic explains the RFX process. This is an advanced topic covering:

  • RFX and the recordset

  • The RFX process

Note

This topic applies to classes derived from CRecordset in which bulk row fetching has not been implemented. If you are using bulk row fetching, bulk record field exchange (Bulk RFX) is implemented. Bulk RFX is similar to RFX. To understand the differences, see Recordset: Fetching Records in Bulk (ODBC).

RFX and the Recordset

The recordset object's field data members, taken together, constitute an edit buffer that holds the selected columns of one record. When the recordset is first opened and is about to read the first record, RFX binds (associates) each selected column to the address of the appropriate field data member. When the recordset updates a record, RFX calls ODBC API functions to send a SQL UPDATE or INSERT statement to the driver. RFX uses its knowledge of the field data members to specify the columns to write.

The framework backs up the edit buffer at certain stages so it can restore its contents if necessary. RFX backs up the edit buffer before adding a new record and before editing an existing record. It restores the edit buffer in some cases, for example, after an Update call following AddNew. The edit buffer is not restored if you abandon a newly changed edit buffer by, for example, moving to another record before calling Update.

Besides exchanging data between the data source and the recordset's field data members, RFX manages binding parameters. When the recordset is opened, any parameter data members are bound in the order of the "?" placeholders in the SQL statement that CRecordset::Open constructs. For more information, see Recordset: Parameterizing a Recordset (ODBC).

Your recordset class's override of DoFieldExchange does all the work, moving data in both directions. Like dialog data exchange (DDX), RFX needs information about the data members of your class. The wizard provides the necessary information by writing a recordset-specific implementation of DoFieldExchange for you, based on the field data member names and data types you specify with the wizard.

Record Field Exchange Process

This section describes the sequence of RFX events as a recordset object is opened and as you add, update, and delete records. The table Sequence of RFX Operations During Recordset Open and the table Sequence of RFX Operations During Scrolling in this topic show the process as RFX processes a Move command in the recordset and as RFX manages an update. During these processes, DoFieldExchange is called to perform many different operations. The m_nOperation data member of the CFieldExchange object determines which operation is requested. You might find it helpful to read Recordset: How Recordsets Select Records (ODBC) and Recordset: How Recordsets Update Records (ODBC) before you read this material.

RFX: Initial Binding of Columns and Parameters

The following RFX activities occur, in the order shown, when you call a recordset object's Open member function:

  • If the recordset has parameter data members, the framework calls DoFieldExchange to bind the parameters to parameter placeholders in the recordset's SQL statement string. A data type-dependent representation of the value of the parameter is used for each placeholder found in the SELECT statement. This occurs after the SQL statement is prepared but before it is executed. For information about statement preparation, see the ::SQLPrepare function in the ODBC Programmer's Reference.

  • The framework calls DoFieldExchange a second time to bind the values of selected columns to corresponding field data members in the recordset. This establishes the recordset object as an edit buffer containing the columns of the first record.

  • The recordset executes the SQL statement and the data source selects the first record. The record's columns are loaded into the recordset's field data members.

The following table shows the sequence of RFX operations when you open a recordset.

Sequence of RFX Operations During Recordset Open

Your operation DoFieldExchange operation Database/SQL operation
1. Open recordset.
2. Build a SQL statement.
3. Send the SQL.
4. Bind parameter data members.
5. Bind field data members to columns.
6. ODBC does the move and fills in the data.
7. Fix up the data for C++.

Recordsets use ODBC's prepared execution to allow for fast requerying with the same SQL statement. For more information about prepared execution, see the ODBC SDK Programmer's Reference in the MSDN Library.

RFX: Scrolling

When you scroll from one record to another, the framework calls DoFieldExchange to replace the values previously stored in the field data members with values for the new record.

The following table shows the sequence of RFX operations when the user moves from record to record.

Sequence of RFX Operations During Scrolling

Your operation DoFieldExchange operation Database/SQL operation
1. Call MoveNext or one of the other Move functions.
2. ODBC does the move and fills in the data.
3. Fix up the data for C++.

RFX: Adding New Records and Editing Existing Records

If you add a new record, the recordset operates as an edit buffer to build up the contents of the new record. As with adding records, editing records involves changing the values of the recordset's field data members. From the RFX perspective, the sequence is as follows:

  1. Your call to the recordset's AddNew or Edit member function causes RFX to store the current edit buffer so it can be restored later.

  2. AddNew or Edit prepares the fields in the edit buffer so RFX can detect changed field data members.

    Because a new record has no previous values to compare new ones with, AddNew sets the value of each field data member to a PSEUDO_NULL value. Later, when you call Update, RFX compares each data member's value with the PSEUDO_NULL value. If there is a difference, the data member has been set. (PSEUDO_NULL is not the same as a record column with a true Null value nor is either of these the same as C++ NULL.)

    Unlike the Update call for AddNew, the Update call for Edit compares updated values with previously stored values rather than using PSEUDO_NULL. The difference is that AddNew has no previously stored values for comparison.

  3. You directly set the values of field data members whose values you want to edit or that you want filled for a new record. This can include calling SetFieldNull.

  4. Your call to Update checks for changed field data members, as described in step 2 (see the table Sequence of RFX Operations During Scrolling). If none have changed, Update returns 0. If some field data members have changed, Update prepares and executes a SQL INSERT statement that contains values for all updated fields in the record.

  5. For AddNew, Update concludes by restoring the previously stored values of the record that was current before the AddNew call. For Edit, the new, edited values remain in place.

The following table shows the sequence of RFX operations when you add a new record or edit an existing record.

Sequence of RFX Operations During AddNew and Edit

Your operation DoFieldExchange operation Database/SQL operation
1. Call AddNew or Edit.
2. Back up the edit buffer.
3. For AddNew, mark field data members as "clean" and Null.
4. Assign values to recordset field data members.
5. Call Update.
6. Check for changed fields.
7. Build SQL INSERT statement for AddNew or UPDATE statement for Edit.
8. Send the SQL.
9. For AddNew, restore the edit buffer to its backed-up contents. For Edit, delete the backup.

RFX: Deleting Existing Records

When you delete a record, RFX sets all the fields to NULL as a reminder that the record is deleted and you must move off it. You do not need any other RFX sequence information.

See Also

Record Field Exchange (RFX)
MFC ODBC Consume
Macros, Global Functions, and Global Variables
CFieldExchange Class
CRecordset::DoFieldExchange