Смекни!
smekni.com

Введение в ADO (стр. 2 из 3)

Пример обработчиков исключений ADO:

void PrintComError(_com_error &e)

{

_bstr_t bstrSource(e.Source());

_bstr_t bstrDescription(e.Description());

// Print COM errors.

printf("Error ");

printf(" Code = %08lx ", e.Error());

printf(" Code meaning = %s ", e.ErrorMessage());

printf(" Source = %s ", (LPCSTR) bstrSource);

printf(" Description = %s ", (LPCSTR) bstrDescription);

}

void PrintProviderError(_ConnectionPtr pConnection)

{

// Print Provider Errors from Connection object.

// pErr is a record object in the Connection's Error collection.

ErrorPtr pErr = NULL;

if( (pConnection->Errors->Count) > 0)

{

long nCount = pConnection->Errors->Count;

// Collection ranges from 0 to nCount -1.

for(long i = 0;i < nCount;i++)

{

pErr = pConnection->Errors->GetItem(i);

printf(" Error number: %x %s", pErr->Number,

pErr->Description);

}

}

}

По умолчанию при установке соединения время ожидания составляет 15 сек. Изменить это значение можно заданием перед открытием соединения свойства ConnectionTimeout.

Если требуется ограничить доступ приложения к источнику данных, перед открытием соединения необходимо установить режим коннекта (свойство Mode объекта Connection). Mode может содержать комбинацию (поразрядное ИЛИ) следующих значений:

adModeRead - Только для чтения

adModeReadWrite - Для чтения/записи.

adModeShareDenyNone - Позволить другим проводить чтение/запись

adModeShareDenyRead - Запретить другим чтение.

adModeShareDenyWrite - Запретить другим запись

adModeShareExclusive - Запретить другим чтение/запись

adModeUnknown - Нет разрешений (по умолчанию)

adModeWrite - Только для записи

6. Закрытие соединения

Завершается работа с источником данных закрытием соединения - вызовом метода Close() объекта Connection.

pConn->Close();

Часть 2.

Итак, продолжим.

7. Наборы записей.

Соединение с источником данных установлено. Далее необходимо собственно эти данные получить и как-то ими управлять. С этой целью создается объект Recordset, который инкапсулирует набор записей, возвращаемых источником. С помощью этого объекта мы сможем добавлять, удалять, изменять записи, в этот объект включен механизм перемещений по записям в наборе данных.

7.1. Создание набора записей.

Объект Recordset можно создать несколькими способами: в результате выполнения команды (использование метода Execute() объекта Command или Connection), или с помощью метода Open() непосредственно объекта Recordset. Рассмотримпоподробнеепоследнийвариант. Итак, метод Open().

HRESULT Open(const _variant_t &Source, const _variant_t &ActiveConnection, enum CursorTypeEnum CursorType, enum LockTypeEnum LockType, long Options);

Source - источник выборки (набора записей). Может быть как SQL строка (запрос), так и имя таблицы или хранимой процедуры на SQL сервере.

ActiveConnection - Соединение, используемое для создание набора записей (выборки). Может быть передано либо в виде строки соединения (при этом отпадает необходимость создания объекта Connection - ADO автоматически создает соединение, которое будет использовано для данного объекта Recordset. Указатель на такое соединение можно получить с помощью свойства объекта Recordset ActiveConnection), либо в виде указателя на уже созданное активное соединение.

CursorType - тип курсора для создаваемого объекта Recordset. Может принимать одно из следующих значений:

adOpenUnspecified - неопределенный тип курсора.

adOpenForwardOnly - односторонний курсор (значение по умолчанию). Не поддерживает методы MoveFirst() (к началу выборки), MoveLast() (к последней записи в выборке), MovePrevious()(к предыдущей записи в выборке). Также не поддерживает использование свойства RecordCount (количество записей в выборке). Не отслеживаются изменения и добавления, сделанные другими пользователями.

adOpenKeyset - курсор, управляемый по ключевому множеству, который может свободно перемещаться и находит некоторые виды изменений, внесенные в строки выборки. Число записей в таком наборе неизменно. Вы не сможете увидеть добавленных другими пользователями записей, удаленные другими пользователями записи остаются видимы в такой выборке, хотя и становятся недоступными.

adOpenDynamic - динамический курсор, который может перемещаться и определять все изменения, внесенные в данные, содержащиеся в выборке. Самый многофункциональный, но и самый дорогой по расходу памяти тип курсора.

adOpenStatic - статический курсор. В отличие от DAO, разрешается модифицировать все ADO Recordset, даже имеющие курсоры adForwardOnly и adOpenStatic. Однако при выборе таких курсоров для выборки все изменения, вносимые другими пользователями для вас невидимы.

LockType - Тип блокировки, используемый данным набором записей. Варианты:

adLockReadOnly - только чтение.

adLockPessimistic - блокирует строки, когда вы начинаете редактирование (если поставщик поддерживает данный тип).

adLockOptimistic - блокирует изменения только при передаче изменений в БД (поддерживается всеми поставщиками данных).

adLockBatchOptimistic - используется для пакетных операций модификации. Пакетная модификация позволяет выгружать множество записей, модифицировать их локально и отсылать изменения поставщику в одном пакете. Большинсто провайдеров не поддерживают эту блокировку.

Options - используется для указания вида Source. Варианты:

adCmdText - текстовая команда (в SQL соглашении).

adCmdTable - таблица или представление (она же - "вьюха", т.е.view).

adCmdStoredProc - хранимая процедура

adCmdUnknown - неизвестный тип (по умолчанию).

Ну что ж, попробуем открыть таблицу authors нашей многострадальной базы данных pubs. Предварительно еще надо определить, будет курсор серверным или клиентским. Сделаем мы это с помощью свойства CursorLocation объекта Recordset (варианты - adUseClient, adUseServer, adUseNone). Можно также ограничить число возвращаемых записей (свойство MaxRecords), задавать количество локально кэшируемых строк в наборе записей (свойство CacheSize - по умолчанию равно единице).

Пример:

_RecordsetPtr pRst;

_bstr_t strTableName = "authors";

pRst.CreateInstance(__uuidof(Recordset));

pRst->CursorLocation = adUseClient;

pRst->MaxRecords = 50;

pRst->CacheSize = 30;

pRst->Open(strTableName,_variant_t((IDispatch*)pConn,true),adOpenDynamic, adLocjOptimistic, adCmdTable);

7.2. Установка фильтра в наборе записей.

В ADO имеется механизм ограничения по какому-либо критерию возвращаемого набора записей - фильтрация выборки. Именно для целей фильтрации объект Recordset обладает свойством Filter.

Свойство Filter представляет собой расширение запроса, заданного в параметре Source Recordset'a. Строка, передаваемая в свойство Filter, должна иметь вид Имя_поля(столбца) - Оператор - Значение, например

pRst->Filter = "au_lname='White AND' au_fname LIKE 'J*' ";

Имя_поля - имя столбца из выборки Recordset.

Оператор - <, >, <=, >=, <>, =, или LIKE

Значение - значение, с которым сравнивается значение поля. Причем для строковых типов данных значение должно быть заключено в одинарные кавычки, для даты значение заключается между символами #. Допускается использование (как и в SQL синтаксисе) символов * и %, например при использовании оператора LIKE. Также допускается применение логических операторов AND и OR для составления комбинированного критерия фильтрации.

Свойство Filter также может принимать значение одной из нижеперечисленных констант:

adFilterNone - Отменяет текущее значение свойства Filter.

adFilterPendingRecords - В режиме пакетной модификации (см.ниже) это значение можно использовать для выбора только из тех строк, которые были изменены, но еще не модифицированы в базе данных.

adFilterAffectedRecords - Выбирает строки, для которых выполнялась последняя операция Delete(), Resync(), UpdateBatch(), CancelBatch().

adFilterFetchedRecords - выбирает строки, которые в настоящее время содержатся в локальном буфере.

7.3. Доступ к данным набора записей.

Информацию о строках (записях) можно получить, используя объекты Field коллекции Fields созданного и открытого Recordset'a.

Коллекция Fields содержит два свойства:

Count - количество столбцов в выборке (более правильно, конечно говорить о количестве объектов Field в коллекции Fields).

Item - предоставляет доступ (возвращает ссылку) к объекту Field по имени или порядковому номеру, т.е. вам становятся доступны такие свойства объекта Field, как имя поля, размер, тип и значение поля.

Покажем это все на примере:

int nNumFields = pRst->Fields->Count;

for(int i=0;i<nNumFields;i++)

{

_bstr_t strName = pRst->Fields->Item[(_variant_t)I]->Name;

_bstr_t strValue = pRst->Fields->Item[(_variant_t)I]->Value;

TRACE(" %S = %S (тип: %d) ", (LPCTSTR)strName, (LPCTSTR) strValue, (short) pRst->Fields->Item(_variant_t)I]->Type);

}

//Или то же самое, но с созданием объектов FieldsPtr и FieldPtr

FieldsPtr pFields;

FieldPtr pField;

pFields= pRst->Fields;

int nNumFields = pFields->Count;

for(int i=0;i<nNumFields;i++)

{

pField = pFields->GetItem((_variant_t)i);

_bstr_t strName =pField->Name;

_bstr_t strValue = pField->Value;

TRACE(" %S = %S (тип: %d) ", (LPCTSTR)strName, (LPCTSTR) strValue, (short) pField->Type);

}

В примере мы выводим данные о полях одной записи (по умолчанию это первая строка выборки). Рассмотрим методы перемещения по выборке данных.

Чтобы перейти к первой строке набора записей можно применить метод MoveFirst() объекта Recordset. Методы MoveNext(), MoveLast() и MovePrevious() позволяют перемещаться по выборке, соответственно, к следующей записи, к последней и предыдущей (если эти перемещения допускает тип курсора).

Объект Recordset имеет свойства EOF и BOF (название свойства EOF мы изменили при подключении msado15.dll - см.выше), которые позволяют определить, что при перемещении по набору записей достигнута последняя (EOF) или первая (BOF) запись. Происходит это следующим образом: если при перемещении по выборке достигнута первая запись, то при следующем вызове MovePrevious() свойство BOF приобретает значение TRUE, аналогично, если позиционирована последняя запись, то при использовании MoveNext() значение TRUE приобретает свойство EOF объекта Recordset.

Пример:

int nNumFields = pRst->Fields->Count;

while(!pRst->ADOEOF){

for(int i=0;i<nNumFields;i++)

{

_bstr_t strName = pRst->Fields->Item[(_variant_t)I]->Name;

_bstr_t strValue = pRst->Fields->Item[(_variant_t)I]->Value;

TRACE(" %S = %S (тип: %d) ", (LPCTSTR)strName, (LPCTSTR) strValue, (short) pRst->Fields->Item(_variant_t)I]->Type);

}

pRst->MoveNext();

}

Также для перемещения по выборке данных можно воспользоваться методом

HRESULT Move(long NumRecords, const _variant_t &Start = vtMissing);

Знаковое целое NumRecords показывает, на сколько записей необходимо переместится по выборке (если NumRecords > 0, то переместиться вперед, если NumRecords < 0, то назад).

Параметр Start задает начальное положение указателя текущей записи (если Start = 0, то перемещение произойдет относительно текущей записи, иначе в Start надо передавать так называемую закладку