行セットでの複数アクセサの使用
更新 : 2007 年 11 月
多重アクセサを使用する必要があるのは、基本的に次の 3 つの場合です。
**複数の読み取り/書き込み行セット。**この場合には、主キーを含むテーブルがあるとします。主キーも含めて行のすべての列を読み取る必要があります。また、主キー列への書き込みはできないため、主キーを除くすべての列にデータを書き込むことができるようにします。この場合は、2 つのアクセサを設定します。
アクセサ 0 はすべての列を含みます。
アクセサ 1 は主キーを除くすべての列を含みます。
**パフォーマンス。**この場合には、1 つ以上の列に大容量のデータが含まれるとします。たとえば、グラフィックス、サウンド、ビデオのファイルなどです。行に移動するたびに大容量のデータ ファイルを含む列を取得することは、アプリケーションのパフォーマンスが低下するため望ましくありません。
この場合は、個別にアクセサを設定できます。最初のアクセサは大容量のデータを含む列以外のすべての列を含み、それらの列から自動的にデータを取得します。このアクセサは、自動アクセサと呼ばれます。2 番目のアクセサは、大容量のデータを含む列だけを取得しますが、この列のデータを自動的には取得しません。その他のメソッドを使用し、要求に応じて大容量のデータを更新またはフェッチできます。
アクセサ 0 は自動アクセサで、大容量のデータを含む列以外の列をすべて取得します。
アクセサ 1 は自動アクセサではなく、大容量のデータを含む列を取得します。
自動アクセサにするかどうかを指定するときは auto 引数を使用します。
**複数の ISequentialStream 列。**この場合には、ISequentialStream データを含む複数の列があるとします。ただし、各アクセサは 1 つの ISequentialStream データ ストリームに制限されます。この問題を解決するには、それぞれが 1 つの ISequentialStream ポインタを含む、複数のアクセサを設定します。
通常、アクセサは BEGIN_ACCESSOR マクロと END_ACCESSOR マクロを使用して作成します。また、db_accessor 属性を使用することもできます。アクセサの詳細については、「ユーザー レコード」を参照してください。アクセサを自動アクセサにするかどうかは、マクロまたは属性によって指定します。
自動アクセサでは、MoveFirst、MoveLast、MoveNext、MovePrev などの移動メソッドによって、指定したすべての列のデータが自動的に取得されます。アクセサ 0 は自動アクセサにする必要があります。
非自動アクセサでは、Update、Insert、Fetch、Delete などのメソッドを明示的に呼び出さない限り、データは取得されません。上のシナリオでは、移動するたびにすべての列を取得すると望ましくない場合があります。以下のように、1 つ以上の列を別のアクセサに入れて、そのアクセサを非自動アクセサにできます。
以下の例では、SQL Server の pubs データベースの jobs テーブルの読み取りと書き込みを行うために、複数のアクセサを使用します。これは最も一般的な複数アクセサの使用例です。上の「複数の読み取り/書き込み行セット」を参照してください。
ユーザー レコード クラスは次のようになります。この例では、2 つのアクセサを設定します。アクセサ 0 には主キー列 (ID) だけが含まれ、アクセサ 1 にはその他の列が含まれます。
class CJobs
{
public:
enum {
sizeOfDescription = 51
};
short nID;
char szDescription[ sizeOfDescription ];
short nMinLvl;
short nMaxLvl;
DWORD dwID;
DWORD dwDescription;
DWORD dwMinLvl;
DWORD dwMaxLvl;
BEGIN_ACCESSOR_MAP(CJobs, 2)
// Accessor 0 is the automatic accessor
BEGIN_ACCESSOR(0, true)
COLUMN_ENTRY_STATUS(1, nID, dwID)
END_ACCESSOR()
// Accessor 1 is the non-automatic accessor
BEGIN_ACCESSOR(1, true)
COLUMN_ENTRY_STATUS(2, szDescription, dwDescription)
COLUMN_ENTRY_STATUS(3, nMinLvl, dwMinLvl)
COLUMN_ENTRY_STATUS(4, nMaxLvl, dwMaxLvl)
END_ACCESSOR()
END_ACCESSOR_MAP()
};
メイン コードは次のとおりです。MoveNext を呼び出すと、アクセサ 0 を使用して、主キー列である ID のデータが自動的に取得されます。コード例の終わりの方にある Insert メソッドでは、主キー列に書き込まないようにアクセサ 1 が使用されます。
int main(int argc, char* argv[])
{
// Initalize COM
::CoInitialize(NULL);
// Create instances of the data source and session
CDataSource source;
CSession session;
HRESULT hr = S_OK;
// Set initialization properties
CDBPropSet dbinit(DBPROPSET_DBINIT);
dbinit.AddProperty(DBPROP_AUTH_USERID, OLESTR("my_user_id"));
dbinit.AddProperty(DBPROP_INIT_CATALOG, OLESTR("pubs"));
dbinit.AddProperty(DBPROP_INIT_DATASOURCE, OLESTR("(local)"));
hr = source.Open("SQLOLEDB.1", &dbinit);
if (hr == S_OK)
{
hr = session.Open(source);
if (hr == S_OK)
{
// Ready to fetch/access data
CTable<CAccessor<CJobs> > jobs;
// Set properties for making the rowset a read/write cursor
CDBPropSet dbRowset(DBPROPSET_ROWSET);
dbRowset.AddProperty(DBPROP_CANFETCHBACKWARDS, true);
dbRowset.AddProperty(DBPROP_CANSCROLLBACKWARDS, true);
dbRowset.AddProperty(DBPROP_IRowsetChange, true);
dbRowset.AddProperty(DBPROP_UPDATABILITY,
DBPROPVAL_UP_INSERT | DBPROPVAL_UP_CHANGE |
DBPROPVAL_UP_DELETE);
hr = jobs.Open(session, "jobs", &dbRowset);
if (hr == S_OK)
{
// Calling MoveNext automatically retrieves ID
// (using accessor 0)
while(jobs.MoveNext() == S_OK)
printf_s("Description = %s\n", jobs.szDescription);
hr = jobs.MoveFirst();
if (hr == S_OK)
{
jobs.nID = 25;
strcpy_s(&jobs.szDescription[0],
jobs.sizeOfDescription,
"Developer");
jobs.nMinLvl = 10;
jobs.nMaxLvl = 20;
jobs.dwDescription = DBSTATUS_S_OK;
jobs.dwID = DBSTATUS_S_OK;
jobs.dwMaxLvl = DBSTATUS_S_OK;
jobs.dwMinLvl = DBSTATUS_S_OK;
// Insert method uses accessor 1
// (to avoid writing to the primary key column)
hr = jobs.Insert(1);
}
jobs.Close();
}
session.Close();
}
source.Close();
}
// Uninitialize COM
::CoUninitialize();
return 0;
}