Utilizzo di più funzioni di accesso per un rowset
Esistono tre scenari di base in cui è necessario usare più funzioni di accesso:
Più set di righe di lettura/scrittura. In questo scenario è presente una tabella con una chiave primaria. Si vuole poter leggere tutte le colonne nella riga, inclusa la chiave primaria. Si vuole anche poter scrivere dati in tutte le colonne ad eccezione della chiave primaria (perché non è possibile scrivere nella colonna chiave primaria). In questo caso, si configurano due funzioni di accesso:
La funzione di accesso 0 contiene tutte le colonne.
La funzione di accesso 1 contiene tutte le colonne ad eccezione della chiave primaria.
Prestazioni. In questo scenario una o più colonne hanno una grande quantità di dati, ad esempio grafica, audio o file video. Ogni volta che si passa a una riga, probabilmente non si vuole recuperare la colonna con il file di dati di grandi dimensioni, perché in questo modo si rallentano le prestazioni dell'applicazione.
È possibile configurare funzioni di accesso separate in cui la prima funzione di accesso contiene tutte le colonne ad eccezione di quella con dati di grandi dimensioni e recupera automaticamente i dati da queste colonne; la prima funzione di accesso è la funzione di accesso automatica. La seconda funzione di accesso recupera solo la colonna che contiene dati di grandi dimensioni, ma non recupera automaticamente i dati da questa colonna. È possibile aggiornare o recuperare i dati di grandi dimensioni su richiesta con altri metodi.
La funzione di accesso 0 è una funzione di accesso automatica; recupera tutte le colonne ad eccezione di quella con dati di grandi dimensioni.
La funzione di accesso 1 non è una funzione di accesso automatica; recupera la colonna con dati di grandi dimensioni.
Utilizzare l'argomento auto per specificare se la funzione di accesso è una funzione di accesso automatica.
Più colonne ISequentialStream. In questo scenario sono presenti più colonne che contengono
ISequentialStream
dati. Tuttavia, ogni funzione di accesso è limitata a unISequentialStream
flusso di dati. Per risolvere questo problema, configurare più funzioni di accesso, ognuna con unISequentialStream
puntatore.
In genere si creano funzioni di accesso usando le macro BEGIN_ACCESSOR e END_ACCESSOR . È anche possibile usare l'attributo db_accessor . (Le funzioni di accesso sono descritte più avanti in Record utente. Le macro o l'attributo specificano se una funzione di accesso è automatica o non automatica:
In una funzione di accesso automatica, spostare automaticamente metodi come
MoveFirst
,MoveNext
MoveLast
, eMovePrev
recuperare i dati per tutte le colonne specificate. La funzione di accesso 0 deve essere la funzione di accesso automatica.In una funzione di accesso non automatica, il recupero non si verifica finché non si chiama in modo esplicito un metodo, ad
Update
esempio ,Insert
Fetch
, oDelete
. Negli scenari descritti in precedenza potrebbe non essere necessario recuperare tutte le colonne in ogni spostamento. È possibile inserire una o più colonne in una funzione di accesso separata e fare in modo che una funzione di accesso non automatica, come illustrato di seguito.
Nell'esempio seguente vengono usate più funzioni di accesso per leggere e scrivere nella tabella dei processi del database pubs di SQL Server usando più funzioni di accesso. Questo esempio è l'uso più comune di più funzioni di accesso; vedere lo scenario "più set di righe di lettura/scrittura" sopra.
La classe di record utente è la seguente. Configura due funzioni di accesso: la funzione di accesso 0 contiene solo la colonna chiave primaria (ID) e la funzione di accesso 1 contiene altre colonne.
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()
};
Il codice principale è il seguente. La chiamata MoveNext
recupera automaticamente i dati dall'ID colonna chiave primaria usando la funzione di accesso 0. Si noti che il Insert
metodo vicino alla fine usa la funzione di accesso 1 per evitare di scrivere nella colonna chiave primaria.
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;
}