Utilizar varios descriptores de acceso en un conjunto de filas
Hay tres escenarios básicos en los que es necesario usar varios descriptores de acceso:
Varios conjuntos de filas de lectura o escritura. En este escenario tiene una tabla con una clave principal. Quiere leer todas las columnas de la fila, incluida la clave principal. También quiere escribir datos en todas las columnas, excepto la clave principal (porque no se puede escribir en la columna de clave principal). En este caso se configuran dos descriptores de acceso:
El descriptor de acceso 0 contiene todas las columnas.
El descriptor de acceso 1 contiene todas las columnas excepto la clave principal.
Rendimiento. En este escenario, una o varias columnas tienen una gran cantidad de datos, por ejemplo, gráficos, sonido o archivos de vídeo. Cada vez que se mueve a una fila probablemente no quiera recuperar la columna con el archivo de datos grande, ya que, al hacerlo, se ralentizaría el rendimiento de la aplicación.
Puede configurar descriptores de acceso independientes en los que el primero contenga todas las columnas excepto la que tiene datos grandes y recupere automáticamente los datos de estas columnas; el primer descriptor de acceso es el descriptor de acceso automático. El segundo descriptor de acceso recupera solo la columna que contiene datos grandes, pero no recupera los datos de esta columna automáticamente. Puede hacer que otros métodos actualicen o capturen los datos grandes a petición.
El descriptor de acceso 0 es un descriptor de acceso automático; recupera todas las columnas excepto la que tiene datos grandes.
El descriptor de acceso 1 no es un descriptor de acceso automático; recupera la columna con datos grandes.
Use el argumento automático para especificar si el descriptor de acceso es automático.
Varias columnas ISequentialStream. En este escenario tiene más de una columna que contiene datos
ISequentialStream
. Pero cada descriptor de acceso está limitado a un flujo de datosISequentialStream
. Para solucionar este problema, configure varios descriptores de acceso, cada uno con un punteroISequentialStream
.
Normalmente los descriptores de acceso se crean mediante las macros BEGIN_ACCESSOR y END_ACCESSOR. También se puede usar el atributo db_accessor. (Los descriptores de acceso se describen más adelante en Registros de usuario). Las macros o el atributo especifican si un descriptor de acceso es automático o no:
En un descriptor de acceso automático, los métodos de movimiento como
MoveFirst
,MoveLast
,MoveNext
yMovePrev
recuperan datos de todas las columnas especificadas automáticamente. El descriptor de acceso 0 debe ser el descriptor de acceso automático.En un descriptor de acceso no automático, la recuperación no se produce hasta que se llama explícitamente a un método como
Update
,Insert
,Fetch
oDelete
. En los escenarios descritos anteriormente, es posible que no quiera recuperar todas las columnas en cada movimiento. Puede colocar una o varias columnas en un descriptor de acceso independiente y convertirla en un descriptor de acceso no automático, como se muestra a continuación.
En el ejemplo siguiente se usan varios descriptores de acceso para leer y escribir en la tabla de trabajos de la base de datos pubs de SQL Server mediante varios descriptores de acceso. Este ejemplo es el uso más común de varios descriptores de acceso; vea el escenario "varios conjuntos de filas de lectura o escritura" arriba.
La clase de registro de usuario es la siguiente. Configura dos descriptores de acceso: el descriptor de acceso 0 contiene solo la columna de clave principal (ID) y el descriptor de acceso 1 contiene otras columnas.
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()
};
El código principal es el siguiente. La llamada a MoveNext
recupera automáticamente los datos del identificador de columna de clave principal mediante el descriptor de acceso 0. Observe cómo el método Insert
situado cerca del final usa el descriptor de acceso 1 para evitar escribir en la columna de clave principal.
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;
}