Použití více přístupových objektů pro sadu řádků
Existují tři základní scénáře, ve kterých potřebujete použít více přístupových objektů:
Více sad řádků pro čtení a zápis V tomto scénáři máte tabulku s primárním klíčem. Chcete mít možnost číst všechny sloupce v řádku, včetně primárního klíče. Chcete také mít možnost zapisovat data do všech sloupců kromě primárního klíče (protože do sloupce primárního klíče nemůžete zapisovat). V tomto případě nastavíte dva přístupové objekty:
Příslušenství 0 obsahuje všechny sloupce.
Přistupovací objekt 1 obsahuje všechny sloupce kromě primárního klíče.
Výkon. V tomto scénáři má jeden nebo více sloupců velké množství dat, například grafiku, zvuk nebo videosoubory. Pokaždé, když přejdete na řádek, pravděpodobně nechcete načíst sloupec s velkým datovým souborem, protože by to zpomalilo výkon vaší aplikace.
Můžete nastavit samostatné přístupové objekty, ve kterých první přístupový objekt obsahuje všechny sloupce s výjimkou sloupců s velkými daty a načítá data z těchto sloupců automaticky; prvním příslušenstvím je automatický přístup. Druhý přístup načte pouze sloupec, který obsahuje velká data, ale nenačítá data z tohoto sloupce automaticky. Můžete mít další metody, které aktualizují nebo načítají velká data na vyžádání.
Příslušenství 0 je automatický příslušenství; načte všechny sloupce s výjimkou sloupců s velkými daty.
Příslušenství 1 není automatickým příslušenstvím; načte sloupec s velkými daty.
Pomocí automatického argumentu určete, zda je příslušenstvím automatického přístupového objektu.
Více sloupců ISequentialStream V tomto scénáři máte více než jeden sloupec, který obsahuje
ISequentialStream
data. Každý přístup je však omezen na jedenISequentialStream
datový proud. Chcete-li tento problém vyřešit, nastavte několik přístupových objektů, z nichž každý má jedenISequentialStream
ukazatel.
Obvykle vytváříte přístupové objekty pomocí BEGIN_ACCESSOR a END_ACCESSOR maker. Můžete také použít atribut db_accessor . (Přístupové objekty jsou podrobněji popsány v tématu Záznamy uživatelů.) Makra nebo atribut určují, jestli je příslušenství automatické nebo neautomatické přístupové objekty:
V automatickém přístupové objektu můžete automaticky přesouvat metody, jako
MoveFirst
je ,MoveLast
MoveNext
, aMovePrev
načítat data pro všechny zadané sloupce. Příslušenství 0 by mělo být automatickým příslušenstvím.V neautomatické přístupové objektu se načítání neprojeví, dokud explicitně nezavoláte metodu, jako
Update
je ,Insert
,Fetch
neboDelete
. Ve scénářích popsaných výše možná nebudete chtít načíst všechny sloupce při každém přesunu. Jeden nebo více sloupců můžete umístit do samostatného přístupového objektu a nastavit ho jako neautomatické příslušenství, jak je znázorněno níže.
Následující příklad používá více přístupových objektů ke čtení a zápisu do tabulky úloh databáze pubs SQL Serveru pomocí více přístupových objektů. Tento příklad je nejběžnějším použitím více přístupových objektů; viz výše uvedený scénář více sad řádků pro čtení a zápis.
Třída záznamu uživatele je následující. Nastaví dva přístupové objekty: přistupovací objekt 0 obsahuje pouze sloupec primárního klíče (ID) a příslušenství 1 obsahuje další sloupce.
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()
};
Hlavní kód je následující. Volání MoveNext
automaticky načte data z ID sloupce primárního klíče pomocí přístupového objektu 0. Všimněte si, jak Insert
metoda blízko konce používá přístupové objekty 1, aby se zabránilo zápisu do sloupce primárního klíče.
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;
}