レコードセット: バルク行フェッチ (ODBC)
このトピックの内容は、MFC ODBC クラスに該当します。
クラス CRecordset
は、バルク行フェッチをサポートしています。つまり、データ ソースから一度に 1 レコードを取得するのではなく、1 回のフェッチで複数のレコードを一度に取得することができます。 バルク行フェッチを実装できるのは、派生した CRecordset
クラスのみです。 データ ソースからレコードセット オブジェクトにデータを転送する処理は、バルク レコード フィールド エクスチェンジ (バルク RFX) と呼ばれます。 CRecordset
派生クラスでバルク行フェッチを使っていない場合、データはレコード フィールド エクスチェンジ (RFX) を介して転送されることに注意してください。 詳細については、「レコード フィールド エクスチェンジ (RFX)」を参照してください。
このトピックでは、次の内容について説明します。
CRecordset がバルク行フェッチをサポートする方法
レコードセット オブジェクトを開く前に、SetRowsetSize
メンバー関数を使って行セット サイズを定義することができます。 行セット サイズには、1 回のフェッチで取得すべきレコード数を指定します。 バルク行フェッチが実装されている場合、既定の行セット サイズは 25 です。 バルク行フェッチが実装されていない場合、行セット サイズは 1 に固定されたままになります。
行セット サイズを初期化した後、Open メンバー関数を呼び出します。 バルク行フェッチを実装するには、ここで dwOptions パラメーターの CRecordset::useMultiRowFetch
オプションを指定する必要があります。 さらに CRecordset::userAllocMultiRowBuffers
オプションを設定できます。 バルク レコード フィールド エクスチェンジ メカニズムでは、フェッチ時に取得された複数行のデータを格納するために配列を使います。 これらのストレージ バッファーは、フレームワークによって自動的に割り当てるか、手動で割り当てることができます。 CRecordset::userAllocMultiRowBuffers
オプションを指定すると、割り当てを実行することになります。
次の表は、バルク行フェッチをサポートするために CRecordset
に用意されているメンバー関数の一覧です。
メンバー関数 | 説明 |
---|---|
CheckRowsetError | フェッチ時に発生したエラーを処理する仮想関数。 |
DoBulkFieldExchange | バルク レコード フィールド エクスチェンジを実装します。 データ ソースからレコードセット オブジェクトに複数行のデータを転送するために自動的に呼び出されます。 |
GetRowsetSize | 行セット サイズに関する現在の設定を取得します。 |
GetRowsFetched | 特定のフェッチ後に実際に取得された行数がわかります。 不完全な行セットがフェッチされた場合を除き、ほとんどの場合、これは行セット サイズです。 |
GetRowStatus | 行セット内の特定の行のフェッチ状態を返します。 |
RefreshRowset | 行セット内の特定の行のデータと状態を更新します。 |
SetRowsetCursorPosition | カーソルを行セット内の特定の行に移動します。 |
SetRowsetSize | 行セット サイズの設定を、指定した値に変更する仮想関数。 |
特別な考慮事項
バルク行フェッチによってパフォーマンスは向上しますが、機能によっては動作が異なります。 バルク行フェッチの実装を決定する前に、次の点を検討してください。
フレームワークによって、自動的に
DoBulkFieldExchange
メンバー関数が呼び出され、データ ソースからレコードセット オブジェクトにデータが転送されます。 ただし、データはレコードセットからデータ ソースに戻されません。AddNew
、Edit
、Delete
、またはUpdate
メンバー関数を呼び出すと、アサーションに失敗します。 現在、CRecordset
にはデータ行を一括して更新するメカニズムが用意されていませんが、ODBC API 関数SQLSetPos
を使って、独自の関数を記述することができます。SQLSetPos
の詳細については、ODBC プログラマーズ リファレンスを参照してください。メンバー関数
IsDeleted
、IsFieldDirty
、IsFieldNull
、IsFieldNullable
、SetFieldDirty
、SetFieldNull
は、バルク行フェッチを実装しているレコードセットに対して使用できません。 ただし、IsDeleted
ではなくGetRowStatus
を、IsFieldNullable
ではなくGetODBCFieldInfo
を呼び出すことはできます。Move
操作により、レコードセットは行セット単位で再配置されます。 たとえば、最初の行セット サイズが 10 で、レコード数が 100 であるレコードセットを開くとします。Open
では、行 1 から 10 をフェッチします。現在のレコードは行 1 に配置されます。MoveNext
を呼び出すと、次の行ではなく、次の行セットがフェッチされます。 この行セットは行 11 から 20 で構成され、現在のレコードは 11 行目に配置されています。 バルク行フェッチが実装されている場合、MoveNext
とMove( 1 )
は同等ではないことに注意してください。Move( 1 )
では、現在のレコードの 1 行目から始まる行セットをフェッチします。 この例では、Open
を呼び出した後にMove( 1 )
を呼び出すと、現在のレコードが 2 行目に配置された、行 2 から 11 で構成される行セットがフェッチされます。 詳細については、Move メンバー関数を参照してください。レコード フィールド エクスチェンジとは異なり、ウィザードはバルク レコード フィールド エクスチェンジをサポートしていません。 つまり、フィールド データ メンバーを手動で宣言し、バルク RFX 関数の呼び出しを記述して
DoBulkFieldExchange
を手動でオーバーライドする必要があります。 詳細については、クラス ライブラリ リファレンスのレコード フィールド エクスチェンジ関数に関するページを参照してください。
バルク レコード フィールド エクスチェンジを実装する方法
バルク レコード フィールド エクスチェンジを使って、データ ソースからレコードセット オブジェクトにデータの行セットを転送します。 バルク RFX 関数には、このデータを格納するための配列と、行セット内の各データ項目の長さを格納するための配列を使います。 クラス定義では、データの配列にアクセスするためのポインターとして、フィールド データ メンバーを定義する必要があります。 さらに、長さの配列にアクセスするポインターのセットを定義する必要があります。 パラメーター データ メンバーは、ポインターとして宣言しないでください。バルク レコード フィールド エクスチェンジを使うときにパラメーター データ メンバーを宣言することは、レコード フィールド エクスチェンジを使うときに宣言することと同じです。 次のコードは、簡単な例を示しています。
class MultiRowSet : public CRecordset
{
public:
// Field/Param Data
// field data members
long* m_rgID;
LPSTR m_rgName;
// pointers for the lengths
// of the field data
long* m_rgIDLengths;
long* m_rgNameLengths;
// input parameter data member
CString m_strNameParam;
.
.
.
}
これらのストレージ バッファーは、手動で割り当てるか、フレームワークで自動的に割り当てることができます。 バッファーを自分で割り当てるには、dwOptions パラメーターの CRecordset::userAllocMultiRowBuffers
オプションを Open
メンバー関数で指定する必要があります。 配列のサイズは、少なくとも行セット サイズと同じに設定してください。 フレームワークで自動的に割り当てる場合は、ポインターを NULL に初期化する必要があります。 通常、これはレコードセット オブジェクトのコンストラクターで行われます。
MultiRowSet::MultiRowSet( CDatabase* pDB )
: CRecordset( pDB )
{
m_rgID = NULL;
m_rgName = NULL;
m_rgIDLengths = NULL;
m_rgNameLengths = NULL;
m_strNameParam = "";
m_nFields = 2;
m_nParams = 1;
.
.
.
}
最後に、DoBulkFieldExchange
メンバー関数をオーバーライドする必要があります。 フィールド データ メンバーの場合は、バルク RFX 関数を呼び出します。任意のパラメーター データ メンバーの場合は、RFX 関数を呼び出します。 Open
に SQL ステートメントまたはストアド プロシージャを渡してレコードセットを開いた場合、バルク RFX 呼び出しを行う順序は、レコードセット内の列の順序に対応している必要があります。同様に、パラメーターに対する RFX 呼び出しの順序は、SQL ステートメントまたはストアド プロシージャ内のパラメーターの順序に対応している必要があります。
void MultiRowSet::DoBulkFieldExchange( CFieldExchange* pFX )
{
// call the Bulk RFX functions
// for field data members
pFX->SetFieldType( CFieldExchange::outputColumn );
RFX_Long_Bulk( pFX, _T( "[colRecID]" ),
&m_rgID, &m_rgIDLengths );
RFX_Text_Bulk( pFX, _T( "[colName]" ),
&m_rgName, &m_rgNameLengths, 30 );
// call the RFX functions for
// for parameter data members
pFX->SetFieldType( CFieldExchange::inputParam );
RFX_Text( pFX, "NameParam", m_strNameParam );
}
Note
派生 CRecordset
クラスがスコープ外に出る前に、Close
メンバー関数を呼び出す必要があります。 こうすることで、フレームワークによって割り当てられたすべてのメモリを解放できます。 バルク行フェッチを実装したかどうかに関係なく、プログラミングの習慣として、常に明示的に Close
を呼び出すことをお勧めします。
レコード フィールド エクスチェンジ (RFX) の詳細については、「レコード フィールド エクスチェンジ: RFX の動作のしくみ」を参照してください。 パラメーターの使用の詳細については、「CFieldExchange::SetFieldType」と「レコードセット: パラメーターを利用したレコードセット (ODBC)」を参照してください。