| |
Реализация доступа к базам данных в среде VISUAL STUDIO.NET на языке С++ с применением MFC
Библиотека MFC
Среда Visual Studio.NET предоставляет различные подходы для реализации работы с базами данных:
- Применение библиотеки MFC (Microsoft Foundation Class Library).
- Применение ATL (Active Template Library).
- Использование библиотек Framework.
Библиотека MFC реализует поддержку доступа к базам данных, основанную на двух механизмах:
- через ODBC-драйверы;
- с применением провайдеров данных OLE DB.
Приложения, использующие доступ к базам данных с применением ODBC-драйверов, в обязательном порядке используют класс CDatabase для создания объекта "база данных" и класс CRecordset для создания объекта "результирующий набор".
Библиотека MFC предоставляет для работы с базами данных через ODBC-драйверы следующие классы:
- CDatabase – класс, инкапсулирующий соединение с источником данных;
- CRecordset – класс, инкапсулирующий работу с результирующим набором, включая переход между записями, добавление, удаление и изменение записей, задание фильтров и выполнение параметризированных запросов;
- CRecordView – класс, предоставляющий средства визуального отображения данных из созданного результирующего набора;
- CDBException – класс, предназначаемый для обработки ошибок, которые возникают при работе с источником данных;
- CFieldExchange – класс, который поддерживает RFX обмен данными между полями – членами класса результирующего набора и столбцами таблицы источника данных.
Библиотека MFC предоставляет для работы с базами данных с применением провайдеров OLE DB класс COleDBRecordView, используемый для отображения данных из результирующего набора (представляемого классом CRowset) в элементах управления шаблона диалога. Этот класс объявляется в заголовочном файле afxoledb.h.
Для реализации клиентов и серверов OLE DB можно использовать ATL, предоставляющую OLE DB шаблоны как С++ шаблоны. Более подробно шаблоны ATL будут рассмотрены в следующей лекции.
Библиотека MFC предоставляет следующие два класса, упрощающие обмен данными:
- CLongBinary – класс, предоставляющий средства работы с BLOB-объектами (Binary Large OBject), такими как bitmap-изображения, хранимыми в базе данных;
- CDBVariant – класс, реализующий тип Variant, который позволяет сохранять информацию в базе данных, используя текущее значение, хранимое в переменной типа union.
Для доступа к конкретной базе данных требуется, чтобы был установлен соответствующий драйвер ODBC или OLE DB провайдер.
Приложения, работающие с базами данных, могут быть реализованы как консольные приложения, приложения с архитектурой документ-отображение (SDI- и MDI-приложения), приложения-диалоги, серверные приложения. |
|
|
Классы для работы с базами данных
Класс CDATABASE
Класс CDatabase предоставляет средства подключения к источнику данных. В приложении может использоваться несколько активных объектов CDatabase.
Для использования класса CDatabase следует подключить заголовочный файл afxdb.h.
Член класса CDatabase::m_hdbc является указателем на подсоединенный ODBC источник данных. Он может использоваться как дескриптор соединения при непосредственном вызове функций ODBC.
Например:
// Использование m_hdbc для непосредственного вызова
// ODBC API.
// m_db – объект типа CDatabase,
// m_hdbc – член класса CDatabase
nRetcode = ::SQLGetInfo( m_db.m_hdbc,
SQL_ODBC_SQL_CONFORMANCE,
&nValue, sizeof( nValue ),
&cbValue );
Класс CDatabase имеет один конструктор без параметров и набор методов, включая следующие:
- OpenEx (LPCTSTR lpszConnectString, DWORD dwOptions = 0);throw (CDBException, CMemoryException ); - метод, выполняющий открытие базы данных. Первый параметр определяет ODBC строку подключения, описывающую источник данных, и некоторую дополнительную информацию, такую как идентификатор пользователя и пароль.
Например: "DSN=SQLServer_Source;UID=Us1;PWD=pwd1".
Второй параметр по умолчанию равен нулю, что предполагает открытие базы данных с разделяемым доступом и с правами записи, без загрузки ODBC Cursor Library DLL и без принудительного отображения диалога ODBC, определяющего информацию для подключения к базе данных. Этот параметр может быть задан как битовая маска, определяемая комбинацией следующих значений:
- CDatabase::openReadOnly – открытие источника данных только для чтения;
- CDatabase::useCursorLib – указывает загрузку библиотеки ODBC Cursor Library DLL, маскирующей некоторую функциональность ODBC-драйвера;
- CDatabase::noOdbcDialog – предотвращает появление диалога для подсоединения источника данных;
- CDatabase::forceOdbcDialog – обеспечивает отображение диалога с целью определения информации для ODBC-соединения.
Например:
// Объявление объекта типа CDatabase
CDatabase m_db1;
// Объект CDatabase: открытие источника данных
// "только на чтение"
m_db1.OpenEx( _T( "DSN=MYDATASOURCE;UID=U1" ),
CDatabase::openReadOnly |
CDatabase::noOdbcDialog ) );
- Close – метод, закрывающий соединение с базой данных. После закрытия соединения объект типа CDatabase можно использовать для открытия другого источника данных;
- IsOpen – метод, определяющий, установлено ли соединение с базой данных для объекта CDatabase;
- GetConnect – метод, который возвращает строку подключения, использованную для открытия источника данных;
- GetDatabaseName – метод, возвращающий имя текущей подсоединенной базы данных (это не источник данных DSN, указываемый для методов OpenEx и Open, и зависит от ODBC);
- CanTransact – метод, позволяющий определить, можно ли использовать транзакции для базы данных;
- SetLoginTimeout – метод, устанавливающий интервал времени, по истечении которого попытка подсоединения к источнику данных будет отменена;
- BeginTrans – метод, открывающий транзакцию. Не все ODBC-драйверы поддерживают применение транзакций;
- CommitTrans – метод, выполняющий завершение транзакции;
- Rollback – метод, выполняющий откат транзакции;
- ExecuteSQL – метод, выполняющий SQL-оператор без возвращения результирующего набора.
Например:
CString strCmd = "UPDATE TBL1 SET F1 = 124";
TRY
{ m_db1.ExecuteSQL( strCmd );}
CATCH(CDBException, e)
{ // Код ошибки в e->m_nRetCode
}
END_CATCH
Класс CRECORDSET
Класс CRecordset реализует операции над результирующим набором, получаемым из источника данных при выполнении SQL-оператора SELECT.
Результирующий набор может использоваться в двух режимах:
- динамический набор записей (dynasets), состояние которого синхронизируется с изменениями, сделанными другими пользователями;
- статический набор записей (snapshots), не отражающий изменения, производимые другими пользователями.
Класс CRecordset позволяет:
- просматривать записи результирующего набора;
- изменять записи;
- выполнять блокировку записей;
- сортировать записи;
- определять фильтр для выбора записей.
Для использования набора записей из базы данных следует:
- Создать объект класса CRecordset, передав конструктору в качестве параметра указатель на объект CDatabase или NULL;
- Вызвать метод Open и определить режим использования набора данных: динамический или статический.
Метод Open создает (открывает) результирующий набор.
Член класса CRecordset::m_hstmt содержит указатель на структуру данных типа HSTMT (дескриптор оператора).
Класс CRecordset содержит переменные и методы для работы с результирующим набором, включая следующие:
- CRecordset::m_nFields – переменная, содержащая количество полей в результирующем наборе.
- CRecordset::m_nParams – переменная, содержащая количество параметров, используемых в запросе.
- CRecordset::m_pDatabase – переменная, содержащая указатель на объект CDatabase посредством которого для данного результирующего набора было установлено соединение с базой данных.
- CRecordset::m_strFilter – переменная, содержащая условие, указываемое во фразе WHERE SQL-оператора (условие должно быть определено до создания результирующего набора вызовом метода Open).
Например:
CMySet rsMySet( NULL ); // Класс CMySet наследуется от CRecordset
// Определение фильтра (условия во фразе WHERE)
rsMySet.m_strFilter = "field2 > 123";
// Выполнение запроса – открытие результирующего набора
rsMySet.Open( CRecordset::snapshot, "MyTbl1" );
- CRecordset::m_strSort – переменная, содержащая значение, указываемое во фразе ORDER BY SQL-оператора;
- CRecordset ( CDatabase* pDatabase = NULL); – конструктор;
- Open – метод, создающий результирующий набор;
- CanAppend – метод, определяющий, разрешено ли в данный открытый набор записей добавлять новые записи;
- GetSQL – метод, возвращающий SQL-оператор, использованный для получения открытого в данный момент результирующего набора;
- IsEOF – метод, определяющий, достигнут ли конец результирующего набора;
- IsBOF – метод, определяющий, достигнуто ли начало набора записей.
Например:
rsSet.Open( ); // Результирующий набор открыт:
// текущая запись - первая
if( rsSet.IsBOF( ) ) return; // Результирующий набор пуст
while ( !rsSet.IsEOF( ) ) // Просмотр всех
// записей от начала до конца
rsSet.MoveNext( );
rsSet.MoveLast( ); // Переход к последней записи
while( !rsSet.IsBOF( ) ) // Просмотр всех
// записей от конца до начала
rsSet.MovePrev( );
rsSet.MoveFirst( ); // Переход к первой записи
- AddNew – метод, используемый для добавления новой записи (только для режима выборки по одной записи);
- CancelUpdate – метод, используемый для отмены изменений, произведенных операциями Edit или AddNew с момента последнего вызова метода Update;
- Delete – метод, используемый для удаления текущей записи;
- Edit – метод, вызываемый для включения режима редактирования текущей записи. В режиме редактирования можно выполнять методы AddNew и Delete. Для внесения изменений, сделанных этими методами, в базу данных следует вызвать метод Update.
Например:
rsSet.Edit( ); // Начало операций изменения записи
rsSet.m_dwF1 = 123;
rsSet.m_strF1 = "abc";
if( !rsCustSet.Update( ) ) // Внесение изменений
- Update – метод, возвращающий ненулевое значение в том случае, если запись источника данных была успешно обновлена;
- MoveFirst – метод, перемещающий указатель текущей записи на первую запись результирующего набора;
- MoveLast – метод, перемещающий указатель текущей записи на последнюю запись результирующего набора;
- MoveNext – метод, перемещающий указатель текущей записи на следующую запись результирующего набора;
- MovePrev – метод, перемещающий указатель текущей записи на предыдущую запись результирующего набора;
- DoFieldExchange – метод, вызываемый для автоматического обмена данными между членами класса – полями результирующего набора (текущей записи) и соответствующими полями текущей записи в источнике данных. Метод DoFieldExchange доступен только для объектов класса, производного от класса CRecordset. Если набор записей создан непосредственно как объект класса CRecordset, то следует использовать метод GetFieldValue. Обмен данными с источником данных, называемый RFX-обменом (record field exchange), работает в двух направлениях: из полей объекта "результирующий набор" в поля источника данных и обратно. Для того чтобы использовать этот метод, достаточно в производном классе результирующего набора определить имена и тип полей данных – членов класса. ClassWizard самостоятельно вставит код в переопределяемый метод DoFieldExchange.
Например:
void CSet::DoFieldExchange(CFieldExchange* pFX)
{
pFX->SetFieldType(CFieldExchange::outputColumn);
RFX_Int(pFX, "F1", m_wF1); // Вызов RFX-метода
RFX_Text(pFX, "F2", m_strF2);
}
Класс CRECORDVIEW
Объект "отображение" типа CRecordView предоставляет средства для просмотра полей базы данных в элементах управления.
Отображение создается на основе шаблона документа, используя элементы управления, добавленные в ресурс шаблона диалога.
Объект CRecordView использует DDX-обмен данными и RFX-обмен данными для реализации обмена между тремя наборами данных: элементами управления, полями результирующего набора и записями источника данных. На следующей схеме проиллюстрировано взаимодействие этих трех наборов данных.
Элементы управления (определяются как ресурсы) |
←DDX-методы |
Поля результирующего набора (определяются как переменные члены класса, наследуемого от CRecordset) |
←RFX-методы |
Поля источника данных (указываются оператором SELECT) |
Класс CRecordView по умолчанию поддерживает реализацию просмотра набора записей и перехода к первой, последней, следующей и предыдущей записям в текущем отображении.
При использовании для создания шаблона приложения MFC Application Wizard автоматически будут созданы ресурс меню и панели инструментов, содержащей кнопки прокрутки набора записей. При программировании вручную, используя ClassWizard, эти ресурсы надо создавать самостоятельно в редакторе меню и в редакторе битовых изображений.
Класс CRecordView имеет два конструктора и набор методов, включая следующие:
- CRecordView – конструктор, параметр которого указывает используемый ресурс шаблона диалога;
- OnGetRecordset – метод, возвращающий указатель на "объект результирующий набор", ассоциированный с отображением, при его успешном создании, и NULL — в противном случае;
- OnMove – метод, используемый для перехода к другой записи результирующего набора. Направление перехода задается параметром, который может принимать следующие значения: ID_RECORD_FIRST; ID_RECORD_LAST; ID_RECORD_NEXT; ID_RECORD_PREV. По умолчанию, OnMove обновляет текущую запись источника данных, если пользователь внес изменения в отображение записи (элементы управления);
- IsOnFirstRecord – метод, возвращающий ненулевое значение, если текущей записью является первая запись результирующего набора.
Для использования базы данных следует:
- Создать объект класса, наследуемого от CDatabase.
- Установить соединение, открыв базу данных (вызвав метод CDatabase::OpenEx или CDatabase::Open).
- Создать объект класса, наследуемого от Crecordset, для операций над подсоединенным источником данных, передав конструктору указатель на CDatabase. Как любой класс, реализующий визуализацию данных, этот класс связывается с шаблоном диалога (шаблон диалога – это ресурс, описывающий диалоговое окно и все располагаемые в нем элементы управления). Используя DDX-механизм (Dialog Data eXchange) обмена данными между результирующим набором и элементами управления, класс CRecordView реализует отображение и изменение данных.
- Для завершения работы закрыть базу данных, вызвав метод CDatabase::Close. Это также закроет все наборы записей.
Создание приложений баз данных
Средства MFC Application Wizard позволяют практически без всякого программирования разрабатывать приложения, выполняющие подключение к таблице базы данных и отображение содержимого ее полей. При этом для реализации доступа к базе данных используется или механизм ODBC, или OLE DB.
Для того чтобы использовать ODBC-драйверы, первоначально следует создать источник данных DSN (Data Source Name). Это можно сделать как в момент формирования проекта с помощью MFC Application Wizard, так и используя ODBC32 панели управления Windows.
При создании источника данных определяется имя источника данных, используемое приложениями, выбирается требуемый для подключения к базе данных ODBC-драйвер и указывается местоположение самой базы данных. Определение имени источника данных выполняется только один раз и затем может быть многократно применяться для создания всех приложений, использующих этот же ODBC-драйвер для этой же базы данных.
Для того, чтобы создать приложение, реализующее доступ к базе данных, выполните следующие действия:
- Создайте новый проект. Выберите в качестве шаблона создаваемого проекта MFC Application.
- Автоматически формируемые приложения, реализующие работу с базой данных, должны поддерживать архитектуру "документ-отображение". (Выберите, например, тип приложения Single Document).
- Перейдите на страницу Database Support и определите поддержку работы с базой данных. Опция Database view without file support обеспечивает формирование кода, выполняющего подключение к источнику данных, но без поддержки механизма сериалицации. Опция Bind all columns доступна только для ODBC и обеспечивает автоматическое связывание полей результирующего набора с переменными членами класса, наследуемого от CRecordset.
- Выберите механизм доступа (Client type):
- опция ODBC обеспечивает включение в проект заголовочного файла AFXDB.H и линкуемых библиотек;
- опция OLE DB обеспечивает включение в проект заголовочных файлов ATLBASE.H, AFXOLEDB.H и ATLPLUS.H.
Если для Database Support была установлена опция Database view without file support или Database view with file support, то для механизма ODBC создаваемый класс отображения будет наследоваться от CRecordView и будет ассоциирован с классом результирующего набора, наследуемого от CRecordset. Для механизма OLE DB класс отображения наследуется от COleDBRecordView и ассоциируется с классом, наследуемым от CTable или CCommand.
- Далее, если используется механизм ODBC, то следует выбрать источник данных, с которым устанавливается соединение. По щелчку мышью на командной кнопке Data Source отображается диалог для выбора источника данных.
- При использовании механизма OLE DB также следует определить источник данных, используя или имя источника данных, или строку подключения
- После определения используемого источника данных и идентификации пользователя отображается диалог со всеми таблицами, представлениями и хранимыми процедурами (только для OLE DB) источника данных, которые доступны данному пользователю. В этом диалоге следует выбрать таблицу базы данных, используемую для формирования результирующего набора.
- На странице Generated Classes отображается список классов, автоматически создаваемый MFC Application Wizard. Класс отображения будет наследован от класса СRecordView, а класс результирующего набора – от класса CRecordset.
Созданное AppWizard приложение будет содержать панель инструментов с кнопками для перехода между записями таблицы базы данных, но не будет содержать элементов управления для отображения полей таблицы базы данных.
Мастер MFC Application Wizard создает в классе, наследуемом от Crecordset, переменные члены класса для каждого поля таблицы подключаемой базы данных.
Для того чтобы отобразить в форме поля базы данных, следует:
- Расположить в редакторе ресурсов для каждого поля таблицы соответствующий ему элемент управления.
- Вставить в метод DoDataExchange класса отображения вызовы методов DDX_FieldText (или DDX_FieldCheck, DDX_FieldRadio, DDX_FieldSlider и т.п.), выполняющие связь между идентификатором ресурса и переменной – членом класса результирующего набора.
Например:
void CP2View::DoDataExchange(CDataExchange* pDX)
{
CRecordView::DoDataExchange(pDX);
DDX_FieldText(pDX,
IDC_EDIT1, // Идентификатор ресурса
m_pSet->m_f1, // Переменная — член
// класса, наследуемого
// от CRecordset
m_pSet); // Член класса, наследуемого
// от CRecordView: CP2Set* m_pSet;
// Член класса, наследуемого от
// CDocument: CP2Set m_P2Set;
// Метод OnInitialUpdate класса
// наследуемого от CRecordView :
// CDocument: CP2Set m_P2Set;
// m_pSet = &GetDocument()->m_P2Set;
DDX_FieldText(pDX,
IDC_EDIT2,
m_pSet->m_f2,
m_pSet);
}
В результате выполненных действий записи базы данных будут отображаться в окне документа в соответствующих элементах управления. |
|
|
|