Чтение онлайн

ЖАНРЫ

Программирование на Visual C++. Архив рассылки

Jenter Алекс

Шрифт:

• установка соединения с БД

• выполнение запросов на выборку и/или изменение данных в БД

• разрыв соединения

ODBC API и классы MFC

MFC предоставляет набор классов, облегчающих работу с ODBC API. Два из них мы рассмотрим подробно – это CDatabase и CRecordset. Хотя эти два класса позволяют выполнять все основные операции по выборке и модификации данных, иногда их возможностей оказывается недостаточно. В этом случае приходится вызывать функции ODBC API напрямую (все эти функции имеют префикс SQL).

Источники данных

Источник данных (data source) – это по сути логическое имя базы данных, которое используется для обращения к ней средствами ODBC.

Эта абстракция оказывается достаточно удобной: если база данных, используемая программой, будет скопирована в другой каталог или перенесена на другой компьютер, нужно просто скорректировать атрибуты источника данных, не внося никаких изменений в саму программу. Однако, ODBC позволяет работать с базой данных и напрямую, то есть без использования источников данных.

БАЗОВЫЕ ВОЗМОЖНОСТИ ODBC

Обработка ошибок

Прежде чем мы приступим к работе с ODBC, нужно научиться обрабатывать ошибки, которые могут возникнуть в процессе выполнения программы. Очень часто ответ на вопрос "почему программа не работает?" находится под рукой; нужно только знать, куда посмотреть.

При использовании ODBC API программист должен был анализировать возвращаемые значения функций, обращаясь за более подробной информацией об ошибке к функции SQLError. MFC скрывает от нас детали этого процесса. В случае возникновения ошибки она возбуждает исключение, которое и должна перехватить наша программа. Обработчик исключения получает указатель на структуру CDBException, которая содержит всю необходимую информацию. Так, поле m_strError содержит описание ошибки в понятной для человека форме, а в m_strStateNativeOrigin записывается пятибуквенный код состояния ODBC, который удобно анализировать в программе, а также некоторая дополнительная информация.

Типичный пример кода обработки исключений выглядит так:

try {

 // Работаем с БД

} catch(CDBException *pException) {

 AfxMessageBox(pException->m_strError);

 pException->Delete; // Удаляем структуру из памяти!

}

Замечу, что обработку исключений следует использовать только для восстановления программы после ошибки. Если всё, что нам требуется – это просмотреть значения полей структуры CDBException, можно сделать это и без перехвата исключений. В режиме отладки Visual C++ сам выводит содержимое структуры CDBException на вкладку Debug в окно Output; так что если ваша программа "рухнула", следует первым делом посмотреть на эту вкладку.

Соединение с базой данных

Сначала поговорим о том, как в системе регистрируются источники данных. Это можно сделать программно или с помощью специальной утилиты – администратора источников данных ODBC. Эта утилита входит в состав Windows и вызывается через панель управления (пункт "Источники данных ODBC (32)"). Программную регистрацию мы рассмотрим во второй части, а пока можно воспользоваться услугами администратора.

Соединение с базой данных в MFC представляется объектом класса CDatabase. Чтобы установить соединение, необходимо воспользоваться функцией CDatabase::OpenEx (функция Open устарела; к тому же пользоваться ею менее удобно). Например:

CDatabase db;

db.OpenEx("DSN=db;UID=sa;PWD=", 0);

Первый параметр функции OpenEx – это строка подключения, в которой пары "параметр=значение" разделяются точкой с запятой. Имена параметров нечувствительны к регистру. В стандартный набор параметров строки соединения входят: DSN (data source name – имя источника данных), UID (имя

пользователя), PWD (пароль) и DRIVER (драйвер ODBC). Большинство драйверов распознаёт ряд дополнительных параметров.

Обратите внимание, что строка соединения не должна начинаться с префикса "ODBC;" (этот префикс нужно было добавлять при использовании функции CDatabase::Open).

Второй параметр функции OpenEx – набор битовых флагов, объединённых логическим "ИЛИ". Вот некоторые из них:

• CDatabase::openReadOnly – открыть БД в режиме "только для чтения".

• CDatabase::noOdbcDialog – никогда не выводить диалог, запрашивающий дополнительную информацию о соединении.

• CDatabase::forceOdbcDialog – всегда выводить диалог, запрашивающий информацию о соединении. Этот режим уместен, если во время написания программы не известно, с какой именно базой данных она будет работать.

По умолчанию (если второй параметр OpenEx не задан или равен 0) база данных открывается в режиме "чтение и запись", а диалог появляется только в случае, когда в строке соединения отсутствуют необходимые параметры (например, имя источника данных).

Выборка данных из таблицы

Работая с ODBC, программа получает данные, извлекаемые из БД, в виде множества записей (recordset). Каждая запись содержит набор полей. В любой заданный момент времени программа может работать только с одной записью (она называется текущей). Используя функции ODBC, можно перемещаться от одной записи к другой. Для удобства каждое поле в результирующем множестве обычно связывается с переменной, которую программа использует для чтения и модификации значения соответствующего поля. Тем не менее, связывать поля с переменными в общем случае необязательно.

В MFC для работы с множеством записей предназначен класс CRecordset. Как правило, этот класс не используется в программе напрямую. Вместо этого от него порождают новые классы, переменные-члены которых и связываются с полями множества записей. Само связывание происходит в виртуальной функции CRecordset::DoFieldExchange, которая переопределяется в производном классе; эта же функция осуществляет обмен данных между полями записи и переменными класса. Множество записей создаётся функцией CRecordset::Open, а перемещение от одной записи к другой осуществляется посредством функций Move, MoveNext, MovePrev и т. п.

Пример

Рассмотрим небольшой пример. Допустим, в базе данных содержится таблица tPeople с полями Name (типа строка из 50 символов) и DateOfBirth (типа дата/время), и мы хотим напечатать на экране её содержимое. Сперва создаём новый класс, порождённый от CRecordset:

class CPeople : public CRecordset {

public:

 CPeople(CDatabase *pDatabase = NULL) : CRecordset(pDatabase) {

m_nFields = 2;

 };

 CString m_Name;

 CTime m_DateOfBirth;

 void DoFieldExchange(CFieldExchange *pFX);

};

Для каждого поля в таблице tPeople мы объявили переменную соответствующего типа. Так, поле Name хранится как строка, поэтому m_Name имеет тип CString. DateOfBirth - это дата, поэтому m_DateOfBirth - переменная типа CTime. Обратите внимание, что в переменную m_nFields (CPeople наследует её от CRecordset) необходимо записать количество полей таблицы (это значение необходимо MFC, чтобы правильно построить запрос). Теперь реализуем функцию DoFieldExchange, в которой происходит связывание полей таблицы с переменными нашего класса CPeople.

Поделиться с друзьями: