テクニカル ノート 43: RFX ルーチン
更新 : 2007 年 11 月
メモ : |
---|
次のテクニカル ノートは、最初にオンライン ドキュメントの一部とされてから更新されていません。結果として、一部のプロシージャおよびトピックが最新でないか、不正になります。最新の情報について、オンライン ドキュメントのキーワードで関係のあるトピックを検索することをお勧めします。 |
ここでは、レコード フィールド エクスチェンジ (RFX: Record Field Exchange) アーキテクチャについて説明します。また、RFX_ プロシージャを作成する方法についても説明します。
RFX の概要
レコードセット フィールド関数はすべて C++ コードで記述されています。特殊なマクロやリソースは使用されていません。RFX 機構の中核は仮想関数であるため、派生したすべてのレコードセット クラスでオーバーライドします。これらの関数は次の形式で記述します。
void CMySet::DoFieldExchange(CFieldExchange* pFX)
{
//{{AFX_FIELD_MAP(CMySet)
<recordset exchange field type call>
<recordset exchange function call>
//}}AFX_FIELD_MAP
}
上のコードで使われている AFX 形式のコメントは、ClassWizard が編集するコード部分を囲んでいます。ClassWizard と互換性のないコードは、この形式のコメントの外側に記述する必要があります。
上の例の <recordset_exchange_field_type_call> は、次のような形式を持ちます。
pFX->SetFieldType(CFieldExchange::outputColumn);
<recordset_exchange_function_call> は、次のような形式を持ちます。
RFX_Custom(pFX, "Col2", m_Col2);
RFX_ 関数の大部分には上のように 3 個の引数がありますが、一部の関数 (RFX_Text や RFX_Binary など) には、さらにオプションの引数があります。
1 つの DoDataExchange 関数に複数の RFX_ を記述できます。
MFC (Microsoft Foundation Class) で提供されるすべての RFX ルーチンについては、afxdb.h を参照してください。
RFX 関数では、CMySet クラスのフィールド データを保存するためのメモリ領域 (通常はデータ メンバ) を登録できます。
備考
レコードセット フィールド関数は、CRecordset クラスだけで使用することを前提にデザインされています。通常は、他の MFC クラスでは使用できません。
データの初期値は C++ 標準コンストラクタによって (通常はコメント ブロック //{{AFX_FIELD_INIT(CMylSet)、//}}AFX_FIELD_INIT の中で) 設定されます。
それぞれの RFX_ 関数は、フィールドが変更されていることを示す状態値を返す操作や、フィールドの編集を行う準備としてフィールド値をアーカイブする操作など、さまざまな操作をサポートする必要があります。
DoFieldExchange を呼び出す各関数 (SetFieldNull、IsFieldDirty など) では、DoFieldExchange 呼び出しに関する初期化を独自に行います。
動作原理
レコード フィールド エクスチェンジを使用するだけの場合は、この後の内容を理解する必要はありません。しかし、処理の背後にある動作原理を理解することによって、独自のエクスチェンジ処理を作成できるようになります。
DoFieldExchange メンバ関数は Serialize メンバ関数と同じように、外部フォームのデータ (ODBC クエリで取得される列データ) とクラスのメンバとの間でデータを取得したり設定したりします。パラメータ pFX はデータ交換のコンテキストを指定します。これは CObject::Serialize の CArchive パラメータに相当します。pFX (CFieldExchange オブジェクト) には操作インジケータがあります。このインジケータは CArchive の方向フラグを一般化したものです。RFX 関数では、次の操作を実行できます。
BindParam : ODBC に渡すパラメータデータの場所を示します。
BindFieldToColumn : ODBC が outputColumn データの検索や書き込みを行う場所を示します。
Fixup : CString/CByteArray の長さを指定し、NULL ステータス ビットを設定します。
MarkForAddNew : AddNew を呼び出した後で値が変更されていれば、変更ありとマークされます。
MarkForUpdate : Edit を呼び出した後で値が変更されていれば、変更ありとマークされます。
Name : 変更ありとマークされているフィールドに名前を追加します。
NameValue : 変更ありとマークされているフィールドに対して "<column name>=?" を追加します。
Value : "?" と区切り記号 (',' または ' ') の並びを追加します。
SetFieldDirty : フィールドが変更されていることを表す (DIRTY) ステータス ビットをオンにします。
SetFieldNull : フィールドが NULL 値であることを表すステータス ビットをオンにします。
IsFieldDirty : DIRTY ステータス ビットの値を返します。
IsFieldNull : NULL ステータス ビットの値を返します。
IsFieldNullable : フィールドが NULL 値を保持できるときは TRUE を返します。
StoreField : フィールド値をアーカイブに保存します。
LoadField : アーカイブからフィールド値を読み出します。
GetFieldInfoValue : フィールドに関する情報を返します。
GetFieldInfoOrdinal : フィールドに関する情報を返します。
ユーザー拡張機能
既定の RFX 機構はいくつかの方法で拡張できます。次のような拡張方法があります。
新しいデータ型を追加する。次に例を示します。
CBookmark
新しいデータ交換プロシージャ (RFX_???) を追加する方法。
void AFXAPI RFX_Bigint(CFieldExchange* pFX, const char *szName, BIGINT& value);
メンバ関数 DoFieldExchange を使用して、状況に応じて RFX 呼び出しやその他の C++ ステートメントを追加する方法。
while (posExtraFields != NULL) { RFX_Text(pFX, m_listName.GetNext(posExtraFields), m_listValue.GetNext(posExtraValues)); }
メモ : |
---|
ClassWizard は、上の例のようなコードを扱えないので、このようなコードは特殊コメント ブロックの外側に記述します。 |
カスタム RFX の作成
新しい RFX 関数を独自に記述するときは、既存の RFX 関数をコピーし、コピーした関数に必要な変更を加えると確実です。適切な RFX 関数を選択してコピーすると、簡単に新しい関数を作成できます。特殊な機能を備えた RFX 関数もあるため、コピーする関数は慎重に選択してください。
RFX_Long および RFX_Int:
最も簡単な RFX 関数です。データ値はそのまま利用されます。また、データ サイズは固定です。RFX_Single および RFX_Double:
RFX_Long、RFX_Int と同様に簡単な関数で、既定の動作を幅広く利用できます。ただし、これらの関数は、明示的に参照されているときにだけ浮動小数点ランタイム ライブラリが読み込まれるように、dbrfx.cpp ではなく dbflt.cpp に記述されています。RFX_Text および RFX_Binary:
文字列とバイナリのデータを保存する静的バッファを事前に確保します。これらのバッファは &value ではなく ODBC SQLBindCol を使用して登録する必要があります。このため、これらの関数には特殊な処理を行うコードが多く含まれます。RFX_Date:
ODBC は日付と時刻を独自の形式のデータ構造 TIMESTAMP_STRUCT で返します。この関数は、日時データの受け渡し用に TIMESTAMP_STRUCT を "プロキシ" として動的に割り当てます。C++ CTime オブジェクトと TIMESTAMP_STRUCT プロキシとの間で行う日時データの交換は、さまざまな処理において必要です。この関数の中身はやや複雑ですが、プロキシを使用したデータ交換例として参考になるはずです。RFX_LongBinary:
この関数は、列を連結せずにデータの受け渡しを行う唯一のクラス ライブラリ RFX 関数です。この関数は BindFieldToColumn 操作を無視します。その代わり、Fixup 操作中に、取得される SQL_LONGVARCHAR データや SQL_LONGVARBINARY データに対してメモリを割り当てます。次に、SQLGetData を呼び出して、割り当てたメモリにデータを取得します。データ ソースにデータ値を戻す (NameValue 操作と Value 操作など) ときは、その準備として ODBC の DATA_AT_EXEC 機能を利用します。SQL_LONGVARBINARY や SQL_LONGVARCHAR の扱い方については、「テクニカル ノート 45: MFC/データベースの Long Varchar/Varbinary 型のサポート」を参照してください。
独自の RFX_ 関数を作成するとき、多くの場合、CFieldExchange::Default を使用して特定の操作を実装できます。必要な操作を実現できるかどうか、Default の実装を調べてみてください。RFX_ 関数に記述しようとしている操作を CFieldExchange::Default で実行できる場合は、CFieldExchange::Default を呼び出して、その操作を任せることができます。CFieldExchange::Default を呼び出す例については、dbrfx.cpp を参照してください。
RFX 関数では、まず IsFieldType を呼び出すことが重要です。IsFieldType が FALSE を返した場合は、すぐに RFX 関数を終了します。このようにすると、パラメータ操作を outputColumns に対して適用してしまうなどの危険 (outputColumn に対して BindParam を呼び出すなど) を回避できます。さらに、IsFieldType は、outputColumns (m_nFields) とパラメータ (m_nParams) の数を自動的に管理します。