Verwenden mehrerer Zugriffsmethoden für ein Rowset
Es gibt drei grundlegende Szenarien, in denen Sie mehrere Accessoren verwenden müssen:
Mehrere Zeilensätze mit Lese-/Schreibzugriff. In diesem Szenario haben Sie eine Tabelle mit einem Primärschlüssel. Sie möchten alle Spalten in der Zeile lesen können, einschließlich des Primärschlüssels. Sie möchten auch Daten in alle Spalten mit Ausnahme des Primärschlüssels schreiben können (da Sie nicht in die Primärschlüsselspalte schreiben können). In diesem Fall richten Sie zwei Accessoren ein:
Accessor 0 enthält alle Spalten.
Accessor 1 enthält alle Spalten mit Ausnahme des Primärschlüssels.
Leistung. In diesem Szenario weist eine oder mehrere Spalten eine große Datenmenge auf, z. B. Grafiken, Sound oder Videodateien. Jedes Mal, wenn Sie zu einer Zeile wechseln, möchten Sie die Spalte mit der großen Datendatei wahrscheinlich nicht abrufen, da dies die Leistung Ihrer Anwendung verlangsamen würde.
Sie können separate Accessoren einrichten, in denen der erste Accessor alle Spalten außer dem mit großen Daten enthält, und daten automatisch aus diesen Spalten abruft. Der erste Accessor ist der automatische Accessor. Der zweite Accessor ruft nur die Spalte ab, die große Daten enthält, aber es werden keine Daten automatisch aus dieser Spalte abgerufen. Sie können andere Methoden aktualisieren oder die großen Daten bei Bedarf abrufen.
Accessor 0 ist ein automatischer Accessor; sie ruft alle Spalten mit Ausnahme der Spalten mit großen Daten ab.
Accessor 1 ist kein automatischer Accessor; sie ruft die Spalte mit großen Daten ab.
Verwenden Sie das auto-Argument, um anzugeben, ob der Accessor ein automatischer Accessor ist.
Mehrere ISequentialStream-Spalten. In diesem Szenario haben Sie mehr als eine Spalte mit
ISequentialStream
Daten. Jeder Accessor ist jedoch auf einenISequentialStream
Datenstrom beschränkt. Um dieses Problem zu lösen, richten Sie mehrere Accessoren ein, die jeweils einenISequentialStream
Zeiger haben.
Normalerweise erstellen Sie Accessoren mithilfe der BEGIN_ACCESSOR und END_ACCESSOR Makros. Sie können auch das attribut db_accessor verwenden. (Accessoren werden weiter in Benutzerdatensätze.) Die Makros oder das Attribut geben an, ob ein Accessor ein automatischer oder nicht automatischer Accessor ist:
Verschieben Sie in einem automatischen Accessor Methoden wie
MoveFirst
,MoveLast
,MoveNext
undMovePrev
rufen Sie Daten für alle angegebenen Spalten automatisch ab. Accessor 0 sollte der automatische Accessor sein.In einem nicht automatischen Accessor tritt der Abruf erst auf, wenn Sie eine Methode wie
Update
, ,Insert
,Fetch
oderDelete
. In den oben beschriebenen Szenarien möchten Sie möglicherweise nicht alle Spalten auf jeder Verschiebung abrufen. Sie können eine oder mehrere Spalten in einem separaten Accessor platzieren und diesen als nicht automatischen Accessor festlegen, wie unten dargestellt.
Im folgenden Beispiel werden mehrere Accessoren zum Lesen und Schreiben in die Auftragstabelle der SQL Server Pubs-Datenbank mit mehreren Accessoren verwendet. Dieses Beispiel ist die am häufigsten verwendete Verwendung mehrerer Accessoren; siehe oben das Szenario "Mehrere Zeilensätze mit Lese-/Schreibzugriff".
Die Benutzerdatensatzklasse lautet wie folgt. Es richtet zwei Accessoren ein: Accessor 0 enthält nur die Primärschlüsselspalte (ID) und Accessor 1 enthält weitere Spalten.
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()
};
Der Hauptcode lautet wie folgt. Durch aufrufen MoveNext
werden automatisch Daten aus der Primärschlüsselspalten-ID mithilfe des Accessors 0 abgerufen. Beachten Sie, wie die Insert
Methode am Ende Accessor 1 verwendet, um das Schreiben in die Primärschlüsselspalte zu vermeiden.
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;
}