уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Уже больше года прошло с момента публикации статьи «SQLite в Delphi 2010.» Надо сказать, что рассмотренный в статье SQLiteWrapper я успешно использовал и в Delphi 2010 и в Delphi XE. Знаю, что есть ещё несколько подобных реализаций для работы с SQLite в Delphi, но почему-то этот wrapper мне понравился более всего — небольшой по размеру, удобный в использовании, простой в изучении. Что ещё для счастья нужно? Никакого паролирования мне для баз SQLite мне не требовалось поэтому использовал себе и использовал разработку Тима Андерсона (Tim Anderson). Но, как говориться, прогресс не стоит на месте и вот вышла Delphi XE2, сама SQLite вроде бы тоже несколько раз «апнулась». Соответственно, поддержка x64, FireMonkey и прочие довольно обширные нововведения в Delphi, а также обновление библиотеки SQLIte.dll внесли свои коррективы в разработку…и мой любимый враппер дал сбой. Нет, он конечно и раньше требовал, например, передачу в параметры методов исключительно AnsiString, но это, можно сказать, мелочи. А тут вдруг после сборки проекта под XE2 перестали работать некоторые методы, например FieldAs…, Bind и пр. Посыпались исключения. Первым делом глянул в репозиторий, но там оказалась ревизия от февраля месяца, т.е. для XE2 не предназначенная, да и среди нововведений значился только бэкап баз данных.

Решил немного пошерстить Сеть в поисках подходящего враппера для SQLite в Delphi XE2. И был приятно удивлен, что разработка Тима Андерсона жива, здорова и даже теперь уже «пышет» кроссплатформенностью. Правда изменились/исчезли некоторые методы, но и добавилось достаточно.  Собственно эту находку я сегодня и решил представить в своем блоге.

В Delphi XE3 добавлена поддержка SQLite. О том, как можно работать с БД SQLite в Delphi XE3 можно узнать из статей «SQLite в Delphi XE3» и «SQLite в Delphi XE3 #2»

Итак, первым делом заходим в репозиторий на Google Code и скачиваем исходники себе на компьютер.

Если не знаете как работать с Google Code — читаем «Совместная работа над проектом. Основы работы с Google Code» и «Совместная работа над проектом. Работа в проектах на Code.Google«.

Итак, что появилось в обновленной версии. Прежде всего — это поддержка Unicode. Теперь все методы работают не с AnsiString как это было в предыдущей версии, а со String, что избавляет от некоторых лишних «телодвижений» при работе с SQLite в Delphi.

Появились типы TDate и TDateTime.

Для класса TSQLiteDatabase:

  • Добавлен метод Attach для добавления к текущему соединению нового файла базу данных (подробнее см. документацию);
  • Добавлен классовый метод AddNewSupportedColumnType;
  • Удален метод BindData
  • Удалены несколько перегруженных методов, таких как GetTable, GetTableString, GetTableValue

Для класса TSQLiteTable

  • Добавлено свойство IsLastRow: boolean
  • Удалено свойство FieldAsString и вместо него добавлено аналогичное — FieldValByNameAsString (зачем? Посмотрим ниже)
Для класса TSQLiteUniTable
  • Добавлен новый метод FindField(const AFieldName: string): TSQLiteField;
  • Добавлены новые свойства FieldsVal, FieldByName, FieldByNameAsString, FieldIndex, SQL, Stmt

Добавлен новый класс TSQLitePreparedStatement

Добавлен новый клсс TSQLiteField

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

Для создания базы данных можете выбрать любую из программ для работы с SQLite, например, рассмотренных в статье «Обзор программ для администрирования баз данных SQLite.«. Я буду пользоваться бесплатной версией SQLite Expert.

Итак, создаем новую базу данных с названием TestSQLite.db и таблицей:

CREATE TABLE [TestTable] (
  [id] INTEGER PRIMARY KEY AUTOINCREMENT, 
  [StringRow] TEXT, 
  [NumberRow] INTEGER, 
  [DateTimeRow] DATETIME);

Теперь создаем новое приложение в Delphi XE2, бросаем в папку с проектом модели SQLite3 и SQLiteTable3 и библиотеку sqlite3.dll.

Добавим на форму приложения 2 кнопки, 4 Label’а и Memo. Внешний вид приложения будет такой:

Теперь создадим три переменные в секции private класса формы:

 Base: TSQLiteDatabase;
 Table: TSQLiteUniTable;
 Stmt: TSQLitePreparedStatement;//новый класс

На OnCreate будем подключаться к БД и получать количество строк в БД. Обработчик будет следующим:

procedure TForm13.FormCreate(Sender: TObject);
var Rows: integer;
begin
  Base := TSQLiteDatabase.Create(ExtractFilePath(Application.ExeName) +
    'TestSQlite.db');
  Stmt := Base.GetPreparedStatement('SELECT count(id) FROM [TestTable]');
  Table:=Stmt.ExecQuery();
  Label4.Caption := Table.FieldsAsString[0];
end;

Теперь напишем обработчик кнопки для записи 1000 значений в БД. Для этого будем использовать в запросе параметры следующим образом:

procedure TForm13.Button1Click(Sender: TObject);
var
  i: integer;
  t: cardinal;
begin
  t := GetTickCount;
  Stmt.SQL :=
    'INSERT INTO [TestTable] ([StringRow], [NumberRow], [DateTimeRow]) VALUES (:str, :int, :date)';
  for i := 0 to 999 do
  begin
    Stmt.ClearParams;
    Stmt.SetParamInt(':int', i);
    Stmt.SetParamText(':str', IntToStr(i));
    Stmt.SetParamDateTime(':date', Now);
    Stmt.PrepareStatement(Stmt.SQL);
    Stmt.ExecQuery();
  end;
  t := GetTickCount - t;
  Label1.Caption := Format('Добавленно %d записей за %d мс', [i, t]);
end;

Посмотрим за какое время при таком подходе в БД запишется 1000 записей:

Больше 86 секунд. Медленно. Попробуем ускорить процесс. Дописываем в обработчик следующий код:

Base.BeginTransaction;
  try
  for i := 0 to 999 do
  begin
    [...]
  end;
  finally
    Base.Commit;
  end;

Проверяем скорость:

Менее 1 секунды на запись 1000 элементов. Неплохо? Транзакции в SQLite рулят =)

Двигаемся далее. Теперь попробуем прочитать первые 1000 записей из базы данных и вывести эти значения в Memo. Так как объект типа TSQLitePreparedStatement у нас уже есть, то нам достаточно сменить SQL-запрос и получить таблицу данных (TSQLiteUniTable). Кстати, при чтении посмотрим в действии новый класс TSQLiteField. Итак, обработчик кнопки на чтение данных из базы:

procedure TForm13.Button2Click(Sender: TObject);
const cStr = '%s - %d - %s';
var t:cardinal;
begin
Memo1.Lines.Clear;
Stmt.SQL:='SELECT * FROM TestTable LIMIT 1000';
Table:=Stmt.ExecQuery;
t := GetTickCount;
 
while not Table.EOF do
  begin
    {получаем по имени поля объект TSQLiteField и получаем значение}
    Memo1.Lines.Add(Format(cStr,[Table.FieldByName['StringRow'].AsString,
                                 Table.FieldByName['NumberRow'].AsInteger,
                                 Table.FieldByName['DateTimeRow'].AsString]));
    Table.Next;
  end;
t := GetTickCount - t;
Label2.Caption := Format('Получено 1000 записей за %d мс', [t]);
end;

У меня чтение 1000 записей и вывод их в Memo заняло чуть больше 1,5 секунд. В приведенном выше коде я использовал работу с новым классом TSQLiteField в котором содержатся методы и свойства необходимые для работы с полями БД.
Итак, что можно сказать по поводу обновленной библиотеки для SQLite в Delphi XE2:

  1. Библиотека стала более соответствовать реальному положению дел в Delphi — поддержка Unicode тому подтверждение.
  2. Новые классы библиотеки, такие как TSQLitePreparedStatement и TSQLiteField, на мой взгляд, делают работы с программой ещё более прозрачной. Так, с помощью TSQLiteDatabase мы можем подключаться к БД, делать резервное копирование, приаттачивать другие базы и т.д., с помощью TSQLitePreparedStatement — управлять запросами к базе данных и получать объекты TSQLiteUniTable, на, а с TSQLiteUniTable мы получаем доступ к не обходимым полям таблицы и, используя возможности TSQLiteField  работать непосредственно со значениями полей. По-моему вполне логично и удобно.
Напомню ещё раз, что исходники библиотеки Вы можете скачать здесь.

Книжная полка

Автор: Дмитрий Осипов
Название:Базы данных и Delphi. Теория и практика
Описание Книга основана на материалах лекций и практических занятий, разработанных автором, и объединяет теоретические основы и практические аспекты разработки реляционных баз данных.
Купить на ЛитРес 383 руб.
Автор: Анатолий Хомоненко, Владимир Гофман
Название:Работа с базами данных в Delphi
Описание: Рассматривается использование средств Delphi для разработки приложений баз данных. Даются понятия баз данных, характеризуются элементы и описываются этапы проектирования реляционных баз данных, изложена технология разработки информационных систем, освещаются приемы работы с данными, создание таблиц и приложений баз данных, подготовка отчетов.
Купить на ЛитРес 151 руб.
0 0 голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
23 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
elpik
elpik
10/10/2011 11:30

Хотелось бы посмотреть на это через интерфейс FMX. т.к. ни одного внятного примера работы с гридами я не нашел. 
В идеале Сверху Memo с запросом, снизу сетка с данными. И было бы неплохо все это расписать от и до.

Linas
10/10/2011 15:52

Thanks for using my wrapper. Accidentally found this post, glad I can understand Russian :) Your data fetch test lasts quite long because while your data is loading your memo control is repainting itself. You could try to write Memo1.Lines.BeginUpdate before loop and Memo1.Lines.EndUpdate after loop. That should speed up things.  In some of my tests I can load 100000 records in less than half a second using TSQLiteUniTable.

elpik
elpik
10/10/2011 18:46

а в FMX вроде как DBGrid отсутствует :) (есть TGrid и TStringGrid), Хотя если честно для меня это было неожиданностью.

elpik
elpik
11/10/2011 02:59

Я сам с SQLite тоже не работал :)
Да это стандартный набор для доступа к БД данным, но если надо сделать произвольный запрос, предполагаю должен использоваться TSQLiteQuery, т.к. в него можно запихать любой запрос. Там есть такой компонент? 
если бы это было VCL то можно было бы использовать   TSQLiteQuery и TDataSource, для свядивания с DBGrid, но в FMX   DBGrid’a  нет, зато в LiveBinding есть TBindScopeDB, предполагаю что для связи с гридом придется использовать его.

Arioch
Arioch
22/10/2011 04:45

elpik — если честно TDB*** давно бы надо убрать, если не совместимость.
Очень уже они ограниченны во первых и запутанны внутри из-за истории тянущейся с Delphi 1 16-bit
Почему нельзя сделать Array of TObject и его published-компоненты засунуть в grid ?
почему нельзя привязать TDBEdit к конкретной строковой переменной ?
 
В том же JediVCL делали свой IDataProvider, правда кроме демонстрашек так и ничего вроде не добавили — т.е. понимать его понимают вроде многие, а вот поставлять данные неоткуда ;-)
 

Arioch
Arioch
22/10/2011 04:47

Блин, если бы FB Embedded научился работать с in-memory таблицами… Ведь почти всё уже сделали.
Но скорее уж NexusDB выпустят
 
Обнаружил, что не хочу пользоваться in-memory таблицами. Все эти master-detail, индексы.
Хочется SQL’я.
 
Zeus вечная альфа, SQLitePass  автора уже год не видно…
Надо эту пробовать :-)

zeroandr
zeroandr
23/10/2011 13:09

Хороший ресурс с актуальными разработками по SQLite  http://blog.synopse.info, там окромя обертки еще много чего имеется :) 

Arioch
Arioch
24/10/2011 17:49

угу… только у меня mORMot даже демку логирования не отработал в XE2

искал «богатый логгер», так и не нашёл, плюнул пока :-)

trackback

[…] Если речь идёт о работе с базами данных, например, с SQLite, то тут на 99,9% случаев придётся использовать таблицы […]

mopsicus
10/02/2012 14:27

кто знает можно ли как-нибудь использовать sqlite.dll из другой директории, а не корневой где ехешник?

Arioch
Arioch
14/02/2012 13:53

а почему нет? я так даже Firebird использовал — а там не одна, а четыре DLLки, да ещё разбросанные по двум папкам.
 
вероятно придется разобраться как библиотека доступа находит и использует DLL — и подправить если нужно — ну так разобраться всегда полезно ;-)
 
 

mopsicus
17/02/2012 11:17

попробовал, не получилось (
не разобрался как этот враппер подгружает ее

mopsicus
17/02/2012 18:16

поспешил) скачал новую версию компонентов и все заработало

Иван
Иван
12/03/2012 21:04

SQLite3_4_Delphi_RC2 + DelphiXe2 = при любой попытке использования вылетает с AccessVioletion at address 0000000…
Печально …

Иван
Иван
13/03/2012 17:09

Переписал всю подсистему отображения данных и потом нашел компоненты с готовым датасетом — Sivak3.
Есть еще odbc драйвера, но в моем случае не подходит.

Brunnen Gi
Brunnen Gi
17/05/2012 13:43

при чтение memo остается пустым!! Хотя подключение к базе проходит и записи добавляются. В чем проблема?

Brunnen Gi
Brunnen Gi
17/05/2012 14:42

Мда. Все утро и до сейчас, это около 6 часов, промучился с чтением. Пока не въехал:
Проблема из волшебной строчки
«Stmt := Base.GetPreparedStatement(‘SELECT count(id) FROM [TestTable]’);»
прописанной на событие OnCreate формы.
Строка
«Stmt.SQL:=’SELECT * FROM [TestTable] LIMIT 1000′;»
ничего вам не даст, пока перед ней вы не пропишите:
«Stmt := Base.GetPreparedStatement(‘SELECT * FROM [TestTable]’);»

Brunnen Gi
Brunnen Gi
17/05/2012 14:57

На твоей странице))
Все копипастил с твоей статьи)

Анонимно
13/05/2016 10:13

При попытке добавления пакета при Install выдает:
—————————
pck_SQLite3_XE2 — Delphi XE2 — Welcome Page [Built]: bds.exe — Entry Point Not Found
—————————
The procedure entry point @Data@Db@TDataSet@IsCursorOpen$qqrv could not be located in the dynamic link library dbrtl160.bpl.

OK