次の方法で共有


テクニカル ノート 53: DAO データベース クラス用カスタム DFX ルーチン

Note

DAO は、Access データベースで使用され、Office 2013 を介してサポートされています。 DAO 3.6 は最終バージョンであり、古いバージョンと見なされます。 Visual C++ 環境およびウィザードでは DAO はサポートされていません (ただし、DAO クラスは含まれており、引き続き使用できます)。 Microsoft は、新しいプロジェクトには OLE DB テンプレートまたは ODBC および MFC を使用することをお勧めします。 DAO は、既存のアプリケーションを保守するためにのみ使用してください。

このテクニカル ノートでは、DAO レコード フィールド エクスチェンジ (DFX) メカニズムについて説明します。 DFX ルーチンで何が起こっているかを理解するために、DFX_Text 関数を例として取り上げ詳しく説明します。 このテクニカル ノートの追加情報として、他の個々の DFX 関数のコードを調査できます。 カスタム DFX ルーチンは、カスタム RFX ルーチン (ODBC データベース クラスで使用される) ほど必要とはされない可能性があります。

このテクニカル ノートの内容は次のとおりです。

DFX の概要

DAO レコード フィールド エクスチェンジ (DFX) メカニズムは、CDaoRecordset クラスを使用するときにデータを取得および更新する手順を簡略化するために使用されます。 このプロセスは、CDaoRecordset クラスのデータ メンバーを使用して簡略化されます。 CDaoRecordset から派生させることで、テーブルまたはクエリの各フィールドを表す派生クラスにデータ メンバーを追加できます。 この "静的バインド" メカニズムは単純ですが、どのアプリケーションでも選択できるデータ フェッチ/更新方法というわけではありません。 DFX は、現在のレコードが変更されるたびに、バインドされたすべてのフィールドを取得します。 通貨が変更された場合にすべてのフィールドをフェッチする必要がない、パフォーマンスを重視するアプリケーションを開発している場合は、CDaoRecordset::GetFieldValue および CDaoRecordset::SetFieldValue を介した "動的バインド" を、データ アクセス方法として選択できます。

Note

DFX と動的バインドは相互排他的ではないので、静的バインドと動的バインドはハイブリッドで使用できます。

例 1 - DAO レコード フィールド エクスチェンジのみの使用

(CDaoRecordset — 派生クラスCMySetが既に開いていると想定します)

// Add a new record to the customers table
myset.AddNew();

myset.m_strCustID = _T("MSFT");

myset.m_strCustName = _T("Microsoft");

myset.Update();

例 2 - 動的バインドのみを使用する

(CDaoRecordset クラス、rs を使用すると想定され、既に開いている)

// Add a new record to the customers table
COleVariant  varFieldValue1 (_T("MSFT"),
    VT_BSTRT);

//Note: VT_BSTRT flags string type as ANSI,
    instead of UNICODE default
COleVariant  varFieldValue2  (_T("Microsoft"),
    VT_BSTRT);

rs.AddNew();

rs.SetFieldValue(_T("Customer_ID"),
    varFieldValue1);

rs.SetFieldValue(_T("Customer_Name"),
    varFieldValue2);

rs.Update();

例 3 - DAO レコード フィールド エクスチェンジと動的バインドの使用

(CDaoRecordset - 派生クラスempを使用して従業員データを参照すると想定します)

// Get the employee's data so that it can be displayed
emp.MoveNext();

// If user wants to see employee's photograph,
// fetch it
COleVariant varPhoto;
if (bSeePicture)
    emp.GetFieldValue(_T("photo"),
    varPhoto);

// Display the data
PopUpEmployeeData(emp.m_strFirstName,
    emp.m_strLastName,
    varPhoto);

DFX のしくみ

DFX メカニズムは、MFC ODBC クラスで使用されるレコード フィールド エクスチェンジ (RFX) メカニズムと同様の方法で動作します。 DFX と RFX の原則は同じですが、内部的な違いは多数あります。 DFX 関数は、事実上すべてのコードが個々の DFX ルーチンによって共有される設計でした。 最高レベルの DFX は、わずかなことしか実行できません。

  • DFX は、必要に応じて SQL SELECT 句と SQL PARAMETERS 句を構築します。

  • DFX は、DAO の GetRows 関数によって使用されるバインディング構造を構築します (詳細については後述します)。

  • DFX は、ダーティ フィールドの検出に使用されるデータ バッファーを管理します (ダブル バッファリングが使用されている場合)。

  • DFX は NULL および DIRTY 状態配列を管理し、更新時に必要に応じて値を設定します。

DFX メカニズムの中心は、CDaoRecordset 派生クラスの DoFieldExchange 関数です。 この関数は、適切な操作の種類の個々の DFX 関数への呼び出しをディスパッチします。 DoFieldExchange を呼び出す前に、内部 MFC 関数は操作の種類を設定します。 次の一覧は、さまざまな操作の種類と簡単な説明を示しています。

操作 説明
AddToParameterList PARAMETERS 句をビルドします
AddToSelectList SELECT 句をビルドします
BindField バインド構造体を設定します
BindParam パラメーター値を設定します
Fixup NULL 状態を設定します
AllocCache ダーティ チェック用のキャッシュを割り当てます
StoreField 現在のレコードをキャッシュに保存します
LoadField キャッシュをメンバー値に復元します
FreeCache キャッシュを解放します
SetFieldNull フィールドの状態と値を NULL に設定します
MarkForAddNew 疑似 NULL ではない場合にフィールドをダーティとしてマークします
MarkForEdit キャッシュと一致しない場合にフィールドをダーティとしてマークします
SetDirtyField ダーティとしてマークされたフィールド値を設定します

次のセクションでは、DFX_Text の各操作について詳しく説明します。

DAO レコード フィールド エクスチェンジ プロセスについて理解するべき最も重要な機能は、CDaoRecordset オブジェクトの GetRows 関数を使用するという点です。 DAO GetRows 関数は、いくつかの方法で動作することが可能です。 このテクニカル ノートでは、GetRows については対象範囲外であるため、簡単にしか説明していません。 DAO GetRows は、いくつかの方法で動作することが可能です。

  • 複数のレコードと複数のデータ フィールドを同時にフェッチできます。 これにより、データ アクセスを高速化し、大規模なデータ構造、各フィールドへの適切なオフセット、構造体内のデータの各レコードを複合的に処理できます。 MFC では、この複数のレコード フェッチ メカニズムは利用されません。

  • GetRows のもう 1 つの動作として、プログラマはデータの 1 レコードに対して、各フィールドの取得されたデータのバインド アドレスを指定できます。

  • また、DAO は、呼び出し元がメモリを割り当てられるようにするために、可変長列の呼び出し元に "コールバック" します。 この 2 つ目の機能は、データのコピー数を最小限に抑えるだけでなく、データをクラス (CDaoRecordset 派生クラス) のメンバーに直接格納できるという利点があります。 この 2 つ目のメカニズムは、MFC が派生クラスのデータ メンバーにバインドするために CDaoRecordset 使用するメソッドです。

カスタム DFX ルーチンの機能

この説明から明らかなのは、DFX 関数で実装される最も重要な操作は、GetRows を正常に呼び出す必須のデータ構造を設定する機能でなければならないということです。 DFX 関数がサポートする必要がある操作は他にも多数存在しますが、GetRows 呼び出しを正しく準備するほど重要なものや複雑なものはありません。

DFX の使用については、オンライン ドキュメントで説明されています。 基本的に、2 つの要件があります。 まず、バインドされたフィールドとパラメーターごとに、CDaoRecordset 派生クラスにメンバーを追加する必要があります。 これに続いて CDaoRecordset::DoFieldExchange をオーバーライドする必要があります。 メンバーのデータ型が重要であることに注意してください。 データベース内のフィールドからのデータと一致するか、少なくともその型に変換可能である必要があります。 たとえば、長整数などのデータベース内の数値フィールドは常にテキストに変換して CString メンバーにバインドできますが、データベース内のテキスト フィールドは必ずしも長整数などの数値表現に変換され、長い整数メンバーにバインドされるとは限りません。 DAO と Microsoft Jet データベース エンジンは、(MFC ではなく) 変換を担当します。

DFX_Text の詳細

前述のように、DFX のしくみを説明する最善の方法は、例を使って作業することです。 この目的のために、DFX_Text の内部動作を調べることは、少なくとも DFX の基本的な理解を得るのにとても役立ちます。

  • AddToParameterList

    この操作により、Jet で必要とされる SQL PARAMETERS 句 ("Parameters <param name>, <param type> ... ;") が作成されます。 各パラメーターは名前が付けられ型指定されます (RFX 呼び出しで指定)。 個々の型の名前を確認するには、CDaoFieldExchange::AppendParamType 関数をご覧ください。 DFX_Text の場合、使用される型は text です。

  • AddToSelectList

    SQL SELECT 句をビルドします。 DFX 呼び出しで指定された列名が追加されるだけであるので ("SELECT <column name>, ...")、これは非常に簡単です。

  • BindField

    最も複雑な操作です。 前に説明したように、ここで、GetRows によって使用される DAO バインド構造が設定されます。 DFX_Text のコードからわかるとおり、構造体内の情報の型には、使用される DAO の種類が含まれます (DFX_Text の場合は DAO_CHAR または DAO_WCHAR)。 さらに、使用されるバインドの種類も設定されます。 前のセクションでは、GetRows については簡単に説明しましたが、MFC で使用されるバインドの種類は、常に直接アドレス バインド (DAOBINDING_DIRECT) であるとの説明で十分です。 さらに、可変長列バインド (DFX_Text など) に加え、コールバック バインドが使用され、MFC でメモリ割り当てを制御し、正しい長さのアドレスを指定できます。 これはつまり、MFC は DAO に対して常に "どこに" データを配置するかを指示して、メンバー変数に直接バインドできることを意味します。 バインド構造の残りの部分には、メモリ割り当てのコールバック関数のアドレスや、列のバインドの型 (列名によるバインド) などの情報が格納されます。

  • BindParam

    これは、パラメーター メンバーに指定されたパラメーター値を使用して SetParamValue を呼び出す単純な操作です。

  • Fixup

    各フィールドの NULL 状態を入力します。

  • SetFieldNull

    この操作では、各フィールドの状態を NULL としてマークするだけで、メンバー変数の値が PSEUDO_NULLに設定されます。

  • SetDirtyField

    ダーティとマークされた各フィールドに対して SetFieldValue を呼び出します。

残りのすべての操作では、データ キャッシュの使用のみが扱われます。 データ キャッシュは、特定の項目をより簡単にするために使用される、現在のレコード内のデータの余分なバッファーです。 たとえば、"ダーティ" フィールドは自動的に検出できます。 オンライン ドキュメントで説明されているように、完全にまたはフィールド レベルでオフにすることができます。 バッファーの実装には、マップを利用します。 このマップは、データの動的に割り当てられたコピーを "バインドされた" フィールド (または CDaoRecordset 派生データ メンバー) のアドレスと照合するために使用されます。

  • AllocCache

    キャッシュされたフィールド値を動的に割り当てて、それをマップに追加します。

  • FreeCache

    キャッシュされたフィールド値を削除し、それをマップから削除します。

  • StoreField

    現在のフィールド値をデータ キャッシュにコピーします。

  • LoadField

    キャッシュされた値をフィールド メンバーにコピーします。

  • MarkForAddNew

    現在のフィールド値が非 NULL かどうかを確認し、必要に応じてダーティとしてマークします。

  • MarkForEdit

    現在のフィールド値とデータ キャッシュを比較し、必要に応じてダーティとしてマークします。

ヒント

標準データ型の既存の DFX ルーチンでカスタム DFX ルーチンをモデル化します。

関連項目

番号順テクニカル ノート
カテゴリ別テクニカル ノート