Использование SQLite в C#: Часть 3 – Основные сценарии работы
Если вы уже имеете опыт работы с классами ADO.NET для MS SQL или Oracle, то освоение методики работы с классами для SQLite не вызовет у вас каких-либо затруднений. Для работы с файлом - источником данных используется класс SQLiteConnection, для работы с SQL-запросами используется класс SQLiteCommand, для получения и обработки результатов выполнения SQL-запросов используется класс SQLiteDataReader, либо SQLiteDataAdapter в связке с универсальными классами DataSet, DataTable и т.п. Простейший сценарий работы с объектом класса SQLiteConnection выглядит следующим образом:
можно также использовать следующую конструкцию:
Строка соединения с источником данных SQLite имеет множество опций, более подробно с ними можно ознакомиться на прекрасном ресурсе www.connectionstrings.com/sqlite/ Если указанный в строке соединения файл не существует, то по умолчанию создается новый файл с указанным именем. При завершении работы с объектом класса SQLiteConnection крайне желательно вызывать метод Dispose() (или использовать конструкцию using), поскольку при выполнении этого метода происходит закрытие соединения и снятие блокировки с файла данных. Если требуется закрыть соединение без уничтожения объекта, то можно использовать метод Close(). Работу с объектами класса SQLiteCommand наглядно рассмотрим на примере создания таблицы и заполнения ее тестовыми данными:
В приведенном примере новый объект класса SQLiteCommand создается вызовом метода CreateCommand() ранее созданного объекта класса SQLiteConnection. В зависимости от сценария работы также можно использовать конструкции:
Текст SQL-команды записывается в свойство CommandText. Строку с командой или содержащую ее переменную также можно передать прямо в в конструктор, например:
Выполнение SQL-команды, не предполагающей возвращения данных, выполняется вызовом метода ExecuteNonQuery(). Выполнение SQL-запроса, предполагающего возвращение единственного значения, выполняется вызовом метода ExecuteScalar():
Для выполнения SQL-команды, предполагающей возврат множества данных, используются два подхода, каждый из которых имеют как плюсы так и минусы. Первый – построчное считывание результатов выполнения команды с помощью объекта класса SQLiteDataReader. Реализация этого подхода требует большее, по сравнению со вторым, количество программного кода, однако дает разработчику несравнимо более богатый набор возможностей для контроля над процессом считывания и обработки данных из результата выполнения SQL-запроса.
В результате выполнения метода ExecuteReader() объекта класса SQLiteCommand создается объект класса SQLiteDataReader. Используя в цикле метод Read() этого объекта, мы последовательно считываем записи результата выполнения SQL-запроса. Для доступа к полям очередной считанной записи имеется целый ряд вариантов, в приведенном примере доступ производится по именам полей, например r["id"]. Также возможны варианты c приведением данных к нужному типу, например GetString() или GetInt32(), однако в качестве параметра вызова они принимают только порядковый номер поля в записи с данными, что не всегда удобно. Можно также разом считать все поля в коллекцию NameValueCollection с помощью метода GetValues(). По окончании считывания данных вызывается метод Close(). Второй подход заключается в считывании данных в объект класса DataSet и последующую работу с ними, как с единой копией-слепком данных. Этот подход удобен для «ленивого» программирования - собирания программы из готовых «кубов» (это даже не кубики).
В приведенных ранее примерах для простоты изложения параметры SQL-команд передавались прямо в тексте команды, что не есть хорошо и безопасно. Корректный подход заключается в передаче параметров запроса в виде отдельного набора объектов класса SQLiteParameter. На примере выполнения команды добавления новых данных приведены несколько вариантов формирования таких параметров.
При программировании многоэтапных сценариев записи или обновления данных разумно использовать транзакции. Для их реализации используется класс SQLiteTransaction. Объект класса создается вызовом метода BeginTransaction () объекта класса SQLiteConnection:
Созданный объект связывается с нужным объектом класса SQLiteCommand:
В случае удачного завершения последовательности действий вызывается метод Commit() класса SQLiteTransaction, а в случае неудачи - метод Rollback(). Обратите внимание на то, как реализована работа с датами в приведенных примерах. Как ранее упоминалось, SQLite не имеет специального типа данных для хранения даты и времени. Наиболее распространенным способом хранения данных значений является целое число секунд, прошедших от точки отчета 1970-01-01 00:00:00 UTC. В приведенных примерах для преобразования даты в целое число используется функция strftime('%s', value), а для обратного преобразования используется функция datetime(value, 'unixepoch'). Также подобные преобразования можно выполнять в программном коде C#, однако это не очень удобно, поскольку в инструментарии языка нет функций для данных преобразований и все придется ваять самостоятельно. |
Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь. Мы рекомендуем Вам зарегистрироваться либо зайти на сайт под своим именем.