テクニカル ノート 53: DAO データベース クラス用カスタム DFX ルーチン
更新 : 2007 年 11 月
メモ : |
---|
Visual C++ .NET では、Visual C++ 開発環境およびウィザードでは DAO はサポートされなくなりました (DAO クラスは含まれているので、このクラスを使うことはできます)。新規プロジェクトの作成には、OLE DB テンプレートまたは ODBC および MFC の使用をお勧めします。DAO は、既存のアプリケーションを保守するためだけに使用してください。 |
ここでは、DAO レコード フィールド エクスチェンジ (DFX: DAO Record Field Exchange) 機構について説明します。DFX ルーチン内の動作が理解できるように、DFX_Text 関数を例にとって詳細に説明します。このテクニカル ノートの補足情報については、その他の DFX 関数のコードを参照してください。カスタム DFX ルーチンは、ODBC データベース クラスで使用されるレコード フィールド エクスチェンジ (RFX: Record Field Exchange) ルーチンよりも使用頻度が少ないはずです。
このノートの内容は次のとおりです。
DFX の概要
例 1 - DAO レコード フィールド エクスチェンジだけを使用する場合
DFX の動作
ユーザー定義の DFX ルーチンで行う処理
DFX_Text の詳細
DFX の概要
DAO レコード フィールド エクスチェンジ機構 (DFX) は、CDaoRecordset クラスを使用するときに、データの検索と更新の手続きを簡略化するために使用します。CDaoRecordset クラスのデータ メンバを使用することで、プロセスが簡単になります。CDaoRecordset の派生クラスを作成し、テーブル内の各フィールドやクエリを表すデータ メンバを追加できます。この "静的連結" 機構は単純ですが、すべてのアプリケーションに適したデータのフェッチおよび更新方法であるとは限りません。DFX は現在のレコードが変更されるたびに、連結されているフィールドをすべて取得します。パフォーマンス重視のアプリケーションの開発中であり、変更のたびにすべてのフィールドをフェッチする必要がない場合は、CDaoRecordset::GetFieldValue と CDaoRecordset::SetFieldValue を通じて "動的連結" する方法でデータにアクセスすることをお勧めします。
メモ : |
---|
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 (Microsoft Foundation Class) の ODBC クラスで利用されるレコード フィールド エクスチェンジ (RFX) 機構と似ています。DFX と RFX の原理は同じですが、数多くの内部的な相違点があります。DFX 関数は、仮想的にすべてのコードが、各 DFX ルーチンで共有されるようにデザインされました。最上位の DFX が行うことは、次のとおりです。
必要に応じて SQL の SELECT 句と PARAMETERS 句を生成します。
DAO の GetRows 関数で使われる連結構造体を生成します (詳細については後述)。
(ダブル バッファリングを使う場合) 変更されているフィールドの検出用データ バッファを管理します。
NULL ステータス配列と DIRTY ステータス配列を管理し、必要に応じて更新時に値を設定します。
DFX 機構の中核は CDaoRecordset の派生クラスの DoFieldExchange 関数です。この関数は、適切な種類の操作を実行するそれぞれの DFX 関数に対する呼び出しをディスパッチします。DoFieldExchange の呼び出しに先立って、MFC 内部の関数によって操作の種類が設定されます。操作の種類ごとの簡単な説明を次の一覧に示します。
操作 |
説明 |
---|---|
AddToParameterList |
PARAMETERS 句の生成 |
AddToSelectList |
SELECT 句の生成 |
BindField |
連結構造体の設定 |
BindParam |
パラメータ値の設定 |
Fixup |
NULL ステータスの設定 |
AllocCache |
変更されているフィールドを検出するキャッシュの割り当て |
StoreField |
現在のレコードをキャッシュに保存 |
LoadField |
キャッシュをメンバの値にリストア |
FreeCache |
キャッシュの解放 |
SetFieldNull |
フィールドのステータスと値を NULL に設定 |
MarkForAddNew |
PSEUDO NULL でい場合は、フィールドが変更されていることをマーク |
MarkForEdit |
キャッシュに一致しない場合は、フィールドが変更されていることをマーク |
SetDirtyField |
変更されているフィールドの値を設定 |
次のセクションでは、DFX_Text について、それぞれの操作を詳細に説明します。
DAO レコード フィールド エクスチェンジのプロセスを理解するうえで最も重要な機能は、CDaoRecordset オブジェクトの GetRows 関数です。DAO の GetRows 関数には何通りかの動作があります。GetRows 関数の詳細についてはこのテクニカル ノートの範囲外のため、ここでは簡潔な説明にとどめます。
DAO の GetRows 関数には何とおりかの動作があります。
複数のレコードと複数のデータのフィールドを一度にフェッチします。これにより、大規模なデータ構造の複雑な処理や、データ構造の各フィールドとレコードに対する適切なオフセットを伴うデータ アクセスが高速化されます。MFC では、複数レコードのフェッチ機構を利用していません。
GetRows のもう 1 つの機能として、プログラマは 1 レコード中の各フィールドについて、検索したデータの連結アドレスを指定できます。
さらに、DAO は、呼び出し側がメモリを割り当てることができるように、可変長列について呼び出し側を "コール バック" します。この機能の利点は、データをコピーする回数を最小限にすると共に、クラス (CDaoRecordset の派生クラス) のメンバの中にデータの直接的な記憶領域を保持できる点です。MFC ではこの方法を使用して、CDaoRecordset の派生クラスのデータ メンバに連結します。
ユーザー定義の DFX ルーチンで行う処理
以上の説明から、どの DFX 関数の場合でも、実装される操作のうち最も重要な機能は、GetRows を正常に呼び出すことができるように、必要なデータ構造を設定することであることがわかります。DFX 関数がサポートする操作は他にも数多くありますが、GetRows の呼び出しの準備に比べれば重要性は低く、複雑でもありません。
DFX の使用方法は、オンライン ドキュメントで説明しています。本質的に、2 つの要件があります。第 1 に、連結されるフィールドおよびパラメータごとに、CDaoRecordset の派生クラスにメンバを追加する必要があります。続いて、CDaoRecordset::DoFieldExchange をオーバーライドする必要があります。メンバのデータ型も重要です。データベースのフィールドのデータと一致する型であるか、少なくともその型に変換できる型であることが必要です。たとえば、データベース内の long integer 型などの数値フィールドは必ずテキストに変換できるため、CString メンバに連結できますが、データベース内のテキスト フィールドは数値表現 (long integer など) に変換して long integer のメンバに連結できるとは限りません。この変換は、MFC ではなく、DAO と Microsoft Jet データベース エンジンが実行します。
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 ルーチンを参考にしてください。 |