Вслед за анонсом новой версии DatabaseLayer, кросс-платформенной библиотеки для работы с базами данных, решил выложить небольшой туториал с примером использования DatabaseLayer.
В этот раз мы рассмотрим пример создания простейшего консольного приложения, использующего эту библиотеку для работы с базами данных.
В качестве среды разработки будем использовать Visual Studio. Это самый простой способ добиться желаемого результата. Бесплатная версия Visual Studio Express Edition тоже вполне подойдет для создания приложений на С++/wxWidgets.
Для начала создадим консольное приложение и назовем его DatabaseLayerMinimal.
В настройках проекта указываем тип приложение Console Application и стамим маркер на Empty Project.
После того как мы создали проект, распаковываем DatabaseLayer рядом с папкой, в которой находится .sln-файл решения.
Затем добавляем в решение проект databaselayer_databaselayer_sqlite.dsp – это проект SqliteDatabaseLayer, который позволяет получить доступ к базам данных SQLite в приложении.
После этого необходимо настроить конфигурации сборки. Открываем Configuration Manager (Build -> Configuration Manager) и устанавливаем для проекта databaselayer_sqlite нужную отладочную и финальную конфигурацию. В нашем примере это Static Unicode Debug Multilib Static и Static Unicode Release Multilib Static.
После этого в нашем проекте приложения необходимо настроить пути для поиска заголовочных файлов, файлов библиотек, а также список дополнительных библиотек для сборки проекта.
Для этого в свойствах проекта в разделе C/C++ -> General в свойстве Additional Include Directories прописываем:
1 | $(SolutionDir)..\databaselayer\include |
В разделе Linker -> General в свойстве Additional Library Directories прописываем:
1 | $(SolutionDir)..\databaselayer\lib\vc_lib |
В разделе Linker -> Input в свойстве Additional Dependencies указываем список необходимых библиоек:
Все, настройку проекта мы закончили, теперь можно заняться написанием кода.
Для каждого сервера баз данных в библиотеке DatabaseLayer существует соответствующий класс соединения. В нашем примере мы будем работать с базой данных SQLite. Для этого будем использовать класс SqliteDatabaseLayer.
Для того чтобы открыть базу данных можно использовать два пути:
- Вызвать конструктор с параметрами и скормить ему путь к базе данных.
- Использовать конструктор без параметров и метод Open().
В нашем примере будет использоваться первый способ.
Для разрыва соединения с базой данных (или для закрытия файла базы данных) используется метод Close().
В библиотеке DatabaseLayer для обработки ошибок используется механизм исключений. Для обработки ошибок необходимо отлавливать исключение DatabaseLayerException.
Итак, минимальное приложение, способное открыть базу данных выглядит так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #include <wx/wx.h> #include <DatabaseLayer.h> #include <SqliteDatabaseLayer.h> #include <DatabaseLayerException.h> int main() { int returnCode(0); DatabaseLayer * connection(NULL); do { try { connection = new SqliteDatabaseLayer(wxT( "Minimal.sqlite" ), false ); } catch (DatabaseLayerException & e) { returnCode = 2; wxPrintf(wxT( "%d %s" ), e.GetErrorCode(), e.GetErrorMessage().GetData()); } } while ( false ); wxDELETE(connection); getchar (); return returnCode; } |
Необходимо помнить, что все ресурсы нужно освобождать руками.
Для выборки данных из таблицы используется метод RunQueryWithResults(), который возвращает указатель но объект DatabaseResultSet
. После работы с результатми запроса, объект DatabaseResultSet
необходимо обязательно закрыть во избежание утечек памяти. Сделать это можно, вызывав метод DatabaseLayer::CloseResultSet()
.
Для обхода записей, возвращенных с помощью метода RunQueryWithResults()
используется метод DatabaseResultSet::Next()
.
Для получения значения поля в классе DatabaseResultSet
существует соответствующий набор методов – GetResultInt()
, GetResultString()
, GetResultBool()
и т.д. Каждый из этих методов может принимать как имя поля, так и порядковый номер (zero-based).
Для запросов, которые не возвращают список записей (INSERT, DELETE) используется метод RunQuery()
.
И вот со всем, описанным выше, мы подошли к рассмотрению более сложного примера – приложение открывает базу данных SQLite, проверяет ее на наличие таблиц. Если таблицы не найдены, то приложение создает одну таблицу и заполняет ее данными. После этого происходит выборка данных и отображение результатов выборки в консоли.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | #include <wx/wx.h> #include <DatabaseLayer.h> #include <SqliteDatabaseLayer.h> #include <DatabaseLayerException.h> int main() { int returnCode(0); DatabaseLayer * connection(NULL); DatabaseResultSet * result(NULL); do { try { connection = new SqliteDatabaseLayer(wxT( "Minimal.sqlite" ), false ); result = connection->RunQueryWithResults( wxT( "SELECT * FROM sqlite_master WHERE type='table'" )); if (!result || !result->Next()) { connection->RunQuery( wxT("CREATE TABLE SampleTable \ (ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, \ Name VARCHAR(32))")); for ( int i = 0; i < 5; i++) { connection->RunQuery(wxString::Format( wxT( "INSERT INTO SampleTable (Name) VALUES ('%i')" ), rand ())); } } if (result) { connection->CloseResultSet(result); result = NULL; } result = connection->RunQueryWithResults(wxT( "SELECT * FROM SampleTable" )); if (!result) { returnCode = 1; break ; } while (result->Next()) { wxPrintf(wxT( "%d - %s\r\n" ), result->GetResultInt(wxT( "ID" )), result->GetResultString(wxT( "Name" )).GetData()); } } catch (DatabaseLayerException & e) { returnCode = 2; wxPrintf(wxT( "%d %s" ), e.GetErrorCode(), e.GetErrorMessage().GetData()); } } while ( false ); if (connection) { if (result) connection->CloseResultSet(result); } wxDELETE(connection); getchar (); return returnCode; } |
7 Comments
roman
Все отлично, но откуда к примеру взять библиотеки comctl32.lib uuid.lib rpcrt4.lib advapi32.lib wxbase28ud.lib wxmsw28ud_core.lib wxcode_msw28ud_databaselayer_sqlite.lib. В архиве их нет.
T-Rex
comctl32.lib uuid.lib rpcrt4.lib advapi32.lib – стандартные, ставятся с Visual Studio
wxbase28ud.lib wxmsw28ud_core.lib – при сборке wxWidgets появляются
wxcode_msw28ud_databaselayer_sqlite.lib – создаются при сборке DatabaseLayer.
Семён
при компиляции mingw-ом я слегка помучался:) разработчики явно его не долюбливают. Чтобы скомпилировать только postgre_sql пришлось править makefile.gcc. В то же время gnumake и VisualStudio позволяют это делать.
И почему то хидеры в архиве только для sqlite. И чтобы скомпилить всю либу под mingw приходится либо makefile править либо качать исходники всех поддерживаемых СУБД.
Но в целом всё получилось неплохо и даже все тесты прошли.
Sam
насколько я понял Databaselayer без dll может работать только с SQLite или я заблуждаюсь?
Я пытаюсь работать с postgres. Следуя доке я конвертнул libpq.dll в libpq.a, а как заставить mingw засунуть эту либу в исполняемый файл понять не могу. Databaselayer компилировал с опциями MONOLITHIC=1, DEBUG=1, WXSHARED=0, SHARED=0…
p.s. а за что мой предыдущий пост удалили?
T-Rex
Какие такие исходники? Для всего есть заголовки/либы в дистрибутивах СУБД. Для Postgres, MySQL точно есть.
T-Rex
Не конвертнул, а создал import library. Это не одно и тоже. import library просто говорит линкеру что некоторые функции лежат не в исполняемом файле а во внешней DLL. И таскать эту dll надо за собой всегда. Это нормально.
Хочется распространять прогу одним файлом? Сделай инсталлятор. в NSIS/NISEdit это за минуту делается
T-Rex
Возможно мне показалось что ты бот