Использование нескольких методов доступа в наборе строк
Обновлен: Ноябрь 2007
Использование нескольких методов доступа требуется, как правило, в трех случаях:
Многократное считывание/запись наборов строк. В этом сценарии у таблицы имеется первичный ключ. Вам необходимо иметь возможность считывания всех столбцов в строке, в том числе первичного ключа. Вам также необходимо иметь возможность записи данных во все столбцы, кроме первичного ключа (поскольку запись в столбец первичного ключа невозможна). В этом случае вы создаете два метода доступа:
В методе доступа 0 содержатся все столбцы.
В методе доступа 1 содержатся все столбцы, кроме первичного ключа.
Производительность. В этом сценарии в нескольких столбцах содержится большой объем данных, например, графические, звуковые файлы или видеоклипы. При каждом переходе в строку не следует извлекать столбец с файлом большого объема, поскольку это может снизить производительность приложения.
Тогда создаются отдельные методы доступа, где в первом методе доступа обрабатываются все столбцы кроме одного с большим объемом данных, а данные из этих столбцов извлекаются автоматически; это метод автоматического доступа. Второй метод извлекает только данные из столбца с большим объемом данных, при этом извлечение из этого столбца не происходит автоматически. Можно использовать и другие методы обновления или доставки данных по требованию.
Метод доступа 0 является автоматическим; он извлекает данные из всех столбцов кроме одного с большим объемом данных.
Метод доступа 1 не является автоматическим; он извлекает данные из столбца с большим объемом данных.
Чтобы указать способ обработки для этого метода, добавьте аргумент auto.
Несколько столбцов ISequentialStream. В этом сценарии обрабатывается несколько столбцов с данными ISequentialStream. При этом каждый метод доступа ограничен одним потоком данных ISequentialStream. Для решения этой проблемы создайте несколько методов доступа, в каждом из которых будет по одному указателю ISequentialStream.
Обычно методы доступа создаются с помощью макросов BEGIN_ACCESSOR и END_ACCESSOR. Можно также использовать атрибут db_accessor. Методы доступа описываются далее в разделе Записи пользователя.) С помощью макросов или атрибута можно указать, является ли метод доступа автоматическим или нет:
При использовании автоматического метода доступа перенесите методы, например, MoveFirst, MoveLast, MoveNext и MovePrev для автоматического извлечения данных из всех указанных столбцов. Метод доступа 0 должен быть автоматическим.
При использовании неавтоматического метода доступа извлечение не начнется до тех пор, пока явно не будет вызван метод, например, Update, Insert, Fetch или Delete. В описанном выше сценарии возможно не потребуется извлечение данных из всех столбцов при каждом переходе. Можно разместить несколько столбцов в отдельный метод доступа и определить его как неавтоматический, как показано ниже.
В следующем примере используется несколько методов доступа при считывании и записи данных в таблицу jobs базы данных SQL Server с именем pubs. Это наиболее типичный пример использования нескольких методов доступа; см. приведенный выше сценарий "многократное считывание/запись наборов строк".
Класс пользовательской записи определяется следующим образом. В нем определены два метода: метод доступа 0 отвечает только за обработку столбца первичного ключа (ID), а метод доступа 1 — за обработку других столбцов.
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()
};
Основные объекты кода выглядят следующим образом. При вызове метода MoveNext выполняется автоматическое извлечение данных из ID столбца первичного ключа с помощью метода 0. Обратите внимание, что метод Insert на завершающем этапе использует метод доступа 1 во избежание записи в столбец первичного ключа.
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;
}