Použití několika přístupových objektů na sadě řádků
Existují tři základní scénáře, ve kterých potřebujete použít více přistupujících objektů:
Více sad řádků pro čtení/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 mít také možnost zapsat data do všech sloupců s výjimkou primárního klíče (protože nelze zapisovat do sloupce primárního klíče). V tomto případě nastavíte dva přistupující objekty:
Přistupující objekt 0 obsahuje všechny sloupce.
Přistupující objekt 1 obsahuje všechny sloupce s výjimkou primárního klíče.
Výkon. V tomto scénáři obsahuje jeden nebo více sloupců velké množství dat, například grafiku, zvuk nebo soubory videa. Pokaždé, když se přesunete na řádek, pravděpodobně nechcete načíst sloupec s velkým datovým souborem, protože to by zpomalilo výkon vaší aplikace.
Můžete nastavit samostatné přistupující objekty, ve kterých první přistupující objekt obsahuje všechny sloupce s výjimkou toho s velkými daty a načítá data z těchto sloupců automaticky; toto je automatický přistupující objekt. Druhý přistupující objekt načítá pouze sloupec, obsahující velká data, ale nenačítá dat z tohoto sloupce automaticky. Můžete mít jiné metody pro aktualizování nebo načítání velkých dat na požádání.
Přistupující objekt 0 je automatický přistupující objekt; načte všechny sloupce kromě toho s velkými daty.
Přistupující objekt 1 není automatický přistupující objekt; načítá sloupec s velkými daty.
Použijte argument auto pro určení, zda je přistupující objekt automatický přistupující objekt.
Více sloupců ISequentialStream. V tomto scénáři máte více než jeden sloupec obsahující ISequentialStream data. Každý přistupující objekt je však omezen na jeden datový proud ISequentialStream. Chcete-li tento problém vyřešit, nastavte několik přistupujících objektů, každý obsahující jeden ukazatel ISequentialStream.
Obvykle vytvoříte přistupující objekty pomocí maker BEGIN_ACCESSOR a END_ACCESSOR. Můžete také použít atribut db_accessor. (Přistupující objekty jsou popsány dále v Záznamech uživatele.) Makra nebo atribut určují, zda je přistupující objekt automatický nebo neautomatický přistupující objekt:
V automatickém přistupujícím objektu metody přesunu MoveFirst, MoveLast, MoveNext a MovePrev načítají data pro všechny zadané sloupce automaticky. Přistupující objekt 0 by měla být automatický přistupující objekt.
V neautomatickém přistupujícím objektu k načtení nedojde, dokud explicitně nezavoláte metodu, jako je Update, Insert, Fetch nebo Delete. V případech popsaných výše není vhodné načítat všechny sloupce při každém přesunu. Můžete umístit jeden nebo více sloupců do samostatného přistupujícího objektu a udělat jej neautomatickým přistupujícím objektem, jak je ukázáno níže.
Následující příklad používá více přistupujících objektů pro čtení a zápis do tabulky jobs databáze pubs serveru SQL Server pomocí více přistupujících objektů. Toto je nejběžnější použití více přistupujících objektů; viz výše scénář "více sad řádků pro čtení/zápis".
Třída záznamu uživatele je jako následující. Nastavuje dva přistupující objekty: přistupující objekt 0 obsahuje pouze sloupec primárního klíče (ID) a přistupující objekt 1 obsahuje jiné 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 jako následující. Volání MoveNext automaticky načítá data ze sloupce primárního klíče ID pomocí přistupujícího objektu 0. Všimněte si, jak metoda Insert poblíž konce používá přistupující objekt 1 pro zamezení zapsání do sloupce primárního klíče.
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;
}