Harrix Блог

  • Списки статей
    • Все статьи
    • IT
    • Qt
    • C++
    • Сложение двух чисел
    • Web программированиe
    • FAQ
    • Latex
    • Установка программ
    • Мифы
    • Видео
    • Про фото
  • Проекты
  • Harrix.org
  • RSS
  • Контакты

Подключение SQLite в проектах Visual Studio в CRL проекте

Как подключать SQLite в Visual Studio С++

11.06.2017 2 комментария 24 434 просмотров

Учебный пример о подключении популярного формата базы данных к проекту. Будем показывать на примере Visual Studio 2017 Community.

Содержание

  • Создание базы данных
  • Создание болванки приложения
  • Код открытия файла
  • Скачивание библиотеки для работы SQLite
  • Подключение библиотеки
  • Подключение к базе данных
  • Выгрузка данных из базы данных
  • Более простой код вывода данных из таблицы
  • Вывод данных из базы данных в таблицу
  • Расширенный пример с кнопкой добавления записи
  • Удаление записи из таблицы

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

По этой статье создайте файл базы данных test.db с одной таблицей students.

Для знающих:

1
2
3
4
5
6
7
8
CREATE TABLE `students` (
`_id` INTEGER PRIMARY KEY AUTOINCREMENT,
`name` TEXT NOT NULL,
`age` INTEGER NOT NULL
);
INSERT INTO `students` VALUES (1,'Дмитрий',20);
INSERT INTO `students` VALUES (2,'Галя',18);
INSERT INTO `students` VALUES (3,'Костя',19);

Создание болванки приложения

Подготовьте приложение с готовой формой. Прочитать об этом можно тут: Visual Studio 2017, Visual Studio 2015, Visual Studio 2010.

Пока разместим на форме кнопку поле вывода.

Также разместим диалоговое окно открытия файлов.

Код открытия файла

Дважды кликаем по кнопке и переходи в код обработки клика кнопки.

И разместим там такой код. Тут пока только получаем имя файла через диалоговое окно и очищаем текстовое поле.

1
2
3
4
5
6
if (openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK) {
    textBox1->Clear();
    String^ fileName = openFileDialog1->FileName;
 
    
}

Скачивание библиотеки для работы SQLite

К сожалению, в Visual Studio нет встроенной поддержки SQLite (В отличии от того же Qt). По идеи, есть в Visual Studio менеджер пакетов NuGet, который позволяет быстро загружать нужные библиотеки, но нужно понимать, что CLR платформа уходит потихоньку, и Microsoft делает упор на C#. В общем, вы сможете загрухить библиотеку через NuGet, но ничего не скомпилируется.

Поэтому будем делать всё вручную.

Идем на сайт https://system.data.sqlite.org.

Там в раздел Download.

И откроется страница, где куча ссылок на разные версии сборок библиотеки. Что же выбрать? Нам точно нужен файл из раздела Precompiled Binaries.

А вот далее четкого ответа вам не дам. Файлов с пометкой Precompiled Binaries много. Они отличаются разрядностью программы (x86 и x64), версией .NET Framework и версией Visual Studio. Причем последний параметр, как оказалось, самый неважный.

Итак, я пишу пример под Visual Studio 2017 Community под Windows 10 x64.

Но CLR приложение компилируется как 32 разрядное приложение (x86). И через .NET Framework 4.5.1.

В общем, у меня сработала библиотека Precompiled Binaries for 32-bit Windows (.NET Framework 4.5.1). Который вообще-то собран под Visual Studio 2013, а не 2017. У вас ввиду других версий Visual Studio и настроек компилятора может потребоваться другой файл.

Внимание! Для Visual Studio 2015 подошел этот же файл. А для Visaul Studio 2010 подошел файл sqlite-netFx40-binary-bundle-Win32-2010-1.0.105.2.zip из раздела Precompiled Binaries for 32-bit Windows (.NET Framework 4.0).

Скачиваем наш файл.

На всякий случай тут его размещаю. Но лучше скачать с сайта.

sqlite-netFx451-binary-bundle-Win32-2013-1.0.105.1.zip

Распаковываем его.

Там нам нужны будут файлы формата .dll.

Размещаем их в какую-нибудь папку. Я разместил в папку C:\Users\[Пользователь]\Documents\Visual Studio 2017\SQLite, но вы можете разместить и в другом месте, где вам захочется.

Подключение библиотеки

Теперь обратно переходим к проекту в Visual Studio. У проекта есть раздел Ссылок к Обозревателе решений.

Щелкаем правой кнопкой по разделу и выбираем Добавить ссылку….

И там через Обзор… выбираем файл System.Data.SQLite.dll

Если после нажатия на OK выскочило сообщение об ошибке, то скорее всего с сайта вы не тот файл скачали.

У вас в разделе Ссылки должно появится упоминание о библиотеке.

Для Visual Studio 2010 подключение ссылки выглядит по другому.

Теперь мы можем в файле кода формы (у меня это MyForm.h) добавить подключение пространств имен библиотек.

1
2
using namespace System::Data::SQLite;
using namespace System::Text;

Вторая строчка к нашей библиотеке не имеет отношения, но функции оттуда нам будут нужны.

Скомпилируйте и запустите программу. Если всё запустилось, то пока вы всё делали правильно.

Подключение к базе данных

Возвращаемся в код кнопки. Там у нас пока прописано открытие файла через диалоговое окно и получение имени выбранного файла.

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

1
2
3
4
5
6
7
8
9
10
11
12
SQLiteConnection ^db = gcnew SQLiteConnection();
try
{
db->ConnectionString = "Data Source=\"" + fileName + "\"";
db->Open();
 
db->Close();
}
finally
{
delete (IDisposable^)db;
}

Скомпилируйте программу и запустите. Проверьте работу кнопки. Если программа не вылетает при выборе файла базы данных test.db, то теперь точно библиотека подключена правильно.

Выгрузка данных из базы данных

Теперь в кнопке мы подключились к базе данных. Попробуем вытащить все данные из таблицы students.

Для этого между строчек db->Open(); и db->Close(); поместим такой код.

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
// Display Table
try
{
SQLiteCommand ^cmdSelect = db->CreateCommand();
cmdSelect->CommandText = "SELECT * FROM students;";
SQLiteDataReader ^reader = cmdSelect->ExecuteReader();
StringBuilder ^sb = gcnew StringBuilder();
for (int colCtr = 0; colCtr < reader->FieldCount; ++colCtr)
{
// Add Seperator (If After First Column)
if (colCtr > 0) sb->Append("|");
 
// Add Column Name
sb->Append(reader->GetName(colCtr));
}
sb->AppendLine();
sb->Append("~~~~~~~~~~~~");
sb->AppendLine();
while (reader->Read())
{
for (int colCtr = 0; colCtr < reader->FieldCount; ++colCtr)
{
// Add Seperator (If After First Column)
if (colCtr > 0) sb->Append("|");
 
// Add Column Text
sb->Append(reader->GetValue(colCtr)->ToString());
}
sb->AppendLine();
}
 
textBox1->Text = sb->ToString();
}
catch (Exception ^e)
{
MessageBox::Show("Error Executing SQL: " + e->ToString(), "Exception While Displaying MyTable ...");
}

Полный код кнопки получается такой.

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
if (openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK) {
textBox1->Clear();
String^ fileName = openFileDialog1->FileName;
 
SQLiteConnection ^db = gcnew SQLiteConnection();
try
{
db->ConnectionString = "Data Source=\"" + fileName + "\"";
db->Open();
 
// Display Table
try
{
SQLiteCommand ^cmdSelect = db->CreateCommand();
cmdSelect->CommandText = "SELECT * FROM students;";
SQLiteDataReader ^reader = cmdSelect->ExecuteReader();
StringBuilder ^sb = gcnew StringBuilder();
for (int colCtr = 0; colCtr < reader->FieldCount; ++colCtr)
{
// Add Seperator (If After First Column)
if (colCtr > 0) sb->Append("|");
 
// Add Column Name
sb->Append(reader->GetName(colCtr));
}
sb->AppendLine();
sb->Append("~~~~~~~~~~~~");
sb->AppendLine();
while (reader->Read())
{
for (int colCtr = 0; colCtr < reader->FieldCount; ++colCtr)
{
// Add Seperator (If After First Column)
if (colCtr > 0) sb->Append("|");
 
// Add Column Text
sb->Append(reader->GetValue(colCtr)->ToString());
}
sb->AppendLine();
}
 
textBox1->Text = sb->ToString();
}
catch (Exception ^e)
{
MessageBox::Show("Error Executing SQL: " + e->ToString(), "Exception While Displaying MyTable ...");
}
 
db->Close();
}
finally
{
delete (IDisposable^)db;
}
}

Запускаем приложение, кликаем на кнопку, выбираем файл test.db. И вы должны увидеть что-то такое.

Вот мы и вывели нашу таблицу в текстовое поле.

Более простой код вывода данных из таблицы

Немного упростил код кнопки, убрав несколько сложных для первого знакомства мест.

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
if (openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK) {
textBox1->Clear();
String^ fileName = openFileDialog1->FileName;
 
SQLiteConnection ^db = gcnew SQLiteConnection();
try
{
db->ConnectionString = "Data Source=\"" + fileName + "\"";
db->Open();
 
try
{
SQLiteCommand ^cmdSelect = db->CreateCommand();
//Обратите внмиание, что SQL запрос оформляем как обычную строчку
cmdSelect->CommandText = "SELECT * FROM students;";
SQLiteDataReader ^reader = cmdSelect->ExecuteReader();
 
//В sb будем записывать итоговый результат
String ^sb = "";
//Пробегаем по каждой записи
while (reader->Read()) {
//В каждой записи пробегаем по всем столбцам
for (int colCtr = 0; colCtr < reader->FieldCount; ++colCtr) {
//Добавлем значение столбца в sb
sb +=  reader->GetValue(colCtr)->ToString();
sb += (" | ");
}
sb += "\r\n";
}
 
//Выводим результат
textBox1->Text = sb->ToString();
}
catch (Exception ^e)
{
MessageBox::Show("Error Executing SQL: " + e->ToString(), "Exception While Displaying MyTable ...");
}
 
db->Close();
}
finally
{
delete (IDisposable^)db;
}
}

Вывод данных из базы данных в таблицу

Мы только что выводили информацию в textBox1. Но это неудобно для вывода таблиц. Выведем в таблицу.

На форме разместил еще одну кнопку и компонент DataGridView.

Вывод данных в таблице будем основывать на статье Вывод таблицы вручную в Visual Studio в CLR приложении.

Будем использовать в коде вектора, так что подключим его через инклуд.

1
#include <cliext/vector>

И через подключение пространства имен.

1
using namespace cliext;

Код клика кнопки.

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
63
if (openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK) {
textBox1->Clear();
String^ fileName = openFileDialog1->FileName;
 
SQLiteConnection ^db = gcnew SQLiteConnection();
try
{
db->ConnectionString = "Data Source=\"" + fileName + "\"";
db->Open();
 
try
{
SQLiteCommand ^cmdSelect = db->CreateCommand();
//Обратите внмиание, что SQL запрос оформляем как обычную строчку
cmdSelect->CommandText = "SELECT * FROM students;";
SQLiteDataReader ^reader = cmdSelect->ExecuteReader();
 
//В table будем записывать итоговый результат
DataTable ^table; //Невидимая таблица данных
DataColumn ^column; //Столбец таблицы
DataRow ^row; //Строка таблицы
 
//Создаем таблицу данных
table = gcnew DataTable();
 
//Вектор названий столбцов
vector<String^>^ nameColumns = gcnew vector<String^>();
 
//Заполним данные о столбцах
for (int i = 0; i < reader->FieldCount; i++) {
nameColumns->push_back(reader->GetName(i));
column = gcnew DataColumn(nameColumns->at(i), String::typeid);
table->Columns->Add(column);
}
 
//Пробегаем по каждой записи
while (reader->Read()) {
//Заполняем строчку таблицы
row = table->NewRow();
//В каждой записи пробегаем по всем столбцам
for (int i = 0; i < reader->FieldCount; i++) {
//Добавлем значение столбца в row
row[nameColumns->at(i)] = reader->GetValue(i)->ToString();
reader->GetValue(i)->ToString();
}
table->Rows->Add(row);
}
 
//Выводим результат
dataGridView1->DataSource = table;
}
catch (Exception ^e)
{
MessageBox::Show("Error Executing SQL: " + e->ToString(), "Exception While Displaying MyTable ...");
}
 
db->Close();
}
finally
{
delete (IDisposable^)db;
}
}

Расширенный пример с кнопкой добавления записи

Мы показали, как считывать данные из SQLite и выводить в таблицу DataGridView. Но у нас сейчас настроенное соединение SQLiteConnection работает только при клике одной кнопки. И, если нам потребуется обращаться к базе данных в других кнопках, то придется создавать новые подключения. Неудобно. Попробуем исправить это.

Задача: Нам нужно, чтобы при нажатию на еще одну кнопку происходило добавление новой записи в базу данных. Причем в отображаемой таблице также происходили изменения.

Как и в предыдущем примере, нам будут нужны вектора, так что не удаляем подключение cliext.

1
#include <cliext/vector>

1
using namespace cliext;

Сделаем переменную подключения к базе данных SQLiteConnection ^db общей для всей нашей формы.

1
SQLiteConnection ^db;

Нам нужно будет в двух кнопках Открыть базу данных и Добавить данные считывать данные из базы данных. Поэтому вынесем заполнение невидимой таблицы DataTable ^table в отдельный метод.

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
private: DataTable^ fillDataTable() {
DataTable ^table;
try
{
SQLiteCommand ^cmdSelect = db->CreateCommand();
//Обратите внимание, что SQL запрос оформляем как обычную строчку
cmdSelect->CommandText = "SELECT * FROM students;";
SQLiteDataReader ^reader = cmdSelect->ExecuteReader();
 
//Переменные
DataColumn ^column; //Столбец таблицы
DataRow ^row; //Строка таблицы
 
//Создаем таблицу данных
table = gcnew DataTable();
 
//Вектор названий столбцов
vector<String^>^ nameColumns = gcnew vector<String^>();
 
//Заполним данные о столбцах
for (int i = 0; i < reader->FieldCount; i++) {
nameColumns->push_back(reader->GetName(i));
column = gcnew DataColumn(nameColumns->at(i), String::typeid);
table->Columns->Add(column);
}
 
//Пробегаем по каждой записи
while (reader->Read()) {
//Заполняем строчку таблицы
row = table->NewRow();
//В каждой записи пробегаем по всем столбцам
for (int i = 0; i < reader->FieldCount; i++) {
//Добавляем значение столбца в row
row[nameColumns->at(i)] = reader->GetValue(i)->ToString();
reader->GetValue(i)->ToString();
}
table->Rows->Add(row);
}
}
catch (Exception ^e)
{
MessageBox::Show("Error Executing SQL: " + e->ToString(), "Exception While Displaying MyTable ...");
}
return table;
}

Закрытие соединения с базой данных вынесем в деструктор формы.

1
db->Close();

Тогда код кнопки открытия базы данных сократится до такого кода.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if (openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK) {
String^ fileName = openFileDialog1->FileName;
 
db = gcnew SQLiteConnection();
try
{
db->ConnectionString = "Data Source=\"" + fileName + "\"";
db->Open();
 
DataTable ^table = fillDataTable();
 
dataGridView1->DataSource = table;
}
catch (Exception ^e)
{
MessageBox::Show("Error Working SQL: " + e->ToString(), "Exception ...");
}
}

Тогда код клика кнопки Добавить запись можно определить так.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
try
{
SQLiteCommand ^cmdInsertValue = db->CreateCommand();
cmdInsertValue->CommandText = "INSERT INTO students (name, age) VALUES('Сандра', 18);";
cmdInsertValue->ExecuteNonQuery();
 
DataTable ^table = fillDataTable();
 
dataGridView1->DataSource = table;
}
catch (Exception ^e)
{
MessageBox::Show("Error Executing SQL: " + e->ToString(), "Exception ...");
}

Удаление записи из таблицы

Напоследок покажем код кнопки, которая удаляет выделенную запись из таблицы. В этом примере из нового появится определение номера выделенной записи в таблице.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Номер выделенной строки
int index = dataGridView1->CurrentCell->RowIndex;
//Определим _id в выделенной строке
String^ _id = dataGridView1->Rows[index]->Cells["_id"]->Value->ToString();
 
try
{
SQLiteCommand ^cmdInsertValue = db->CreateCommand();
cmdInsertValue->CommandText = "DELETE FROM students WHERE _id = " + _id+ ";";
cmdInsertValue->ExecuteNonQuery();
 
DataTable ^table = fillDataTable();
 
dataGridView1->DataSource = table;
}
catch (Exception ^e)
{
MessageBox::Show("Error Executing SQL: " + e->ToString(), "Exception ...");
}

Обратите внимание на то, что при нажатии на кнопки Добавить запись и Удалить запись вначале мы производим изменения в базе данных, а потом заново из базы данных выгружаем данные.

Исходники проекта под Visual Studio 2017 WorkWithSqlite.zip.


Статьи по теме:

  1. Создание класса с вектором экземпляров другого класса на C++/CLI
  2. Разбор XML файла с применением классов на C++/CLI
  3. Вывод таблицы вручную в Visual Studio в CLR приложении
  4. Сложение двух чисел в Visual Studio 2010 (консольное Win32 приложение)

IT C++, C++/CLI, SQLite, Visual Studio

© 2014 Harrix