テクニカル ノート 43: RFX ルーチン

更新 : 2007 年 11 月

959hh9b7.alert_note(ja-jp,VS.90).gifメモ :

次のテクニカル ノートは、最初にオンライン ドキュメントの一部とされてから更新されていません。結果として、一部のプロシージャおよびトピックが最新でないか、不正になります。最新の情報について、オンライン ドキュメントのキーワードで関係のあるトピックを検索することをお勧めします。

ここでは、レコード フィールド エクスチェンジ (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_TextRFX_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 を呼び出す各関数 (SetFieldNullIsFieldDirty など) では、DoFieldExchange 呼び出しに関する初期化を独自に行います。

動作原理

レコード フィールド エクスチェンジを使用するだけの場合は、この後の内容を理解する必要はありません。しかし、処理の背後にある動作原理を理解することによって、独自のエクスチェンジ処理を作成できるようになります。

DoFieldExchange メンバ関数は Serialize メンバ関数と同じように、外部フォームのデータ (ODBC クエリで取得される列データ) とクラスのメンバとの間でデータを取得したり設定したりします。パラメータ pFX はデータ交換のコンテキストを指定します。これは CObject::SerializeCArchive パラメータに相当します。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));
    }
    
959hh9b7.alert_note(ja-jp,VS.90).gifメモ :

ClassWizard は、上の例のようなコードを扱えないので、このようなコードは特殊コメント ブロックの外側に記述します。

カスタム RFX の作成

新しい RFX 関数を独自に記述するときは、既存の RFX 関数をコピーし、コピーした関数に必要な変更を加えると確実です。適切な RFX 関数を選択してコピーすると、簡単に新しい関数を作成できます。特殊な機能を備えた RFX 関数もあるため、コピーする関数は慎重に選択してください。

  • RFX_Long および RFX_Int:
    最も簡単な RFX 関数です。データ値はそのまま利用されます。また、データ サイズは固定です。

  • RFX_Single および RFX_Double:
    RFX_LongRFX_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_LONGVARBINARYSQL_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) の数を自動的に管理します。

参照

その他の技術情報

番号順テクニカル ノート

カテゴリ別テクニカル ノート