在資料列集上使用多重存取子
有三個基本案例,您需要使用多個存取子:
多個讀取/寫入數據列集。 在此案例中,您有具有主鍵的數據表。 您想要能夠讀取資料列中的所有資料行,包括主鍵。 您也想要將數據寫入主鍵以外的所有資料列(因為您無法寫入主鍵數據行)。 在此情況下,您會設定兩個存取子:
存取子 0 包含所有資料行。
存取子 1 包含主鍵以外的所有數據行。
效能: 在此案例中,一或多個數據行具有大量數據,例如圖形、音效或視訊檔案。 每次移至資料列時,您可能不想使用大型資料檔擷取數據行,因為這樣做會降低應用程式的效能。
您可以設定個別的存取子,其中第一個存取子包含除具有大型數據的數據以外的所有數據行,而且會自動從這些數據行擷取數據;第一個存取子是 auto 存取子。 第二個存取子只會擷取保存大型數據的數據行,但不會自動從這個數據行擷取數據。 您可以讓其他方法視需要更新或擷取大型數據。
存取子 0 是自動存取子;它會擷取除了具有大型數據的數據行以外的所有數據行。
存取子 1 不是自動存取子;它會擷取具有大型數據的數據行。
使用 auto 自變數來指定存取子是否為自動存取子。
多個 ISequentialStream 數據行。 在此案例中,您有超過一個數據行持有
ISequentialStream
數據。 不過,每個存取子限制為一個ISequentialStream
數據流。 若要解決此問題,請設定數個存取子,每個存取子都有一個ISequentialStream
指標。
您通常會使用 BEGIN_ACCESSOR 和 END_ACCESSOR 宏來建立存取子。 您也可以使用 db_accessor 屬性。 (存取子會在 中 進一步說明使用者記錄。)宏或 屬性會指定存取子是自動存取子或非自動存取子:
在自動存取子中,移動方法,例如
MoveFirst
、MoveLast
、MoveNext
和MovePrev
自動擷取所有指定數據行的數據。 存取子 0 應該是自動存取子。在非自動存取子中,除非您明確呼叫 、、
Fetch
或Delete
等Update
Insert
方法,否則不會發生擷取。 在上述案例中,您可能不想在每次移動時擷取所有數據行。 您可以將一或多個數據行放在不同的存取子中,並使該數據行成為非自動存取子,如下所示。
下列範例使用多個存取子,使用多個存取子讀取和寫入 SQL Server pubs 資料庫的作業數據表。 此範例是多個存取子最常見的用法;請參閱上面的「多個讀取/寫入數據列集」案例。
用戶記錄類別如下所示。 它會設定兩個存取子:存取子 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()
};
主要程序代碼如下所示。 使用存取子 0,呼叫 MoveNext
會自動從主鍵數據行標識符擷取數據。 請注意結尾附近的 方法如何使用 Insert
存取子 1,以避免寫入主鍵數據行。
int main(int argc, char* argv[])
{
// Initialize 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;
}