среда, 5 февраля 2014 г.

Среда разработки Lazarus+ сервер баз данных Firebird

Я начал, но не закончил написание вот такой пошаговой инструкции (может сгодится кому):
Задача: Написать простую программу демонстрирующую принципы работы с базами данных по сети в целом и сервером баз данных FireBird в частности.
Нужно:
- Программы : FireBird - сервер баз данных, Lazarus – бесплатный аналог Делфи, IB/FB Development Studio – средство разработки баз данных для FireBird (получается файл с расширением *.FBD) – все эти программы бесплатны, русскоязычны, их можно счкачать из Интернета.
FireBird берем не выше версии 2.0 – более поздние версии не поддерживаются IB/FB Development Studio.

Задача: Написать простую программу демонстрирующую принципы работы с базами данных по сети в целом и сервером баз данных FireBird в частности. (как правило когда программист первый раз пробует написать программу работающую с БД он пишет телефонный справочник  :-) 
Нужно:
-  Программы : FireBird  - сервер баз данных, Lazarus – бесплатный аналог Делфи, IB/FB Development Studio – средство разработки баз данных для FireBird (получается файл с расширением *.FBD) – все эти программы бесплатны, русскоязычны, их можно счкачать из Интернета.
FireBird  берем не выше версии 2.0 – более поздние версии не поддерживаются IB/FB Development Studio.
Запустим IB/FB Development Studio и создадим базу данных C:\BAZA.FDB, а в той базе таблицу
(после запуска программы выбираем «Редактор Баз данных», затем  нажимаем кнопку «создать базу»

Появится диалоговое окно, заполните его как на рисунке ниже   (напоминаю – пароль masterkey)

И жмем кнопку «Создать». База создана.
Теперь создайте в ней таблицу следующей структуры:
Таблица ANKETA
N-integer
Family, Name, Info – char , кодировка UTF8
N
Family
Name
INFO
1
Иванов
Иван
Постоянно опаздывает на работу. Разгильдяй и неряха.
2
Петров
Петр
Пунктуален, подтянут, вежлив. Подозрительный тип.


Не забудьте сохранить

Теперь заполним таблицу первичными данными


Закроем редактор БД.
Запустим Lazarus
Поместим на форму компоненты TIBConnectiom , TSQLTransaction, TSQLQuery из панели SQLbd; и компонент TDatasource из панели Data Access.

Настроим связи между этими компонентами.
  • В свойстве Transaction объекта IBConnectiom1 выберите SQLTransaction1 (я не менял присваиваемые по умолчанию имена объектов).

  • В свойстве Database объекта SQLQuery1 выберите IBConnectiom1
  • В свойстве Transaction объекта SQLQuery1 выберите SQLTransaction1
  • В свойстве DataSet объекта Datasource1 выберите SQLQuery1
Для подключения к базе данных необходимо для объекта IBConnectiom1 указать адрес сервера (свойство HostName, если же FireBird установлен прям на этом компьютере, то оставляем поле пустым), название базы данных (свойство DatabaseName), имя пользователя (свойство UserName – по умолчанию для Firebird - SYSDBA) и пароль для доступа к базе данных (свойство Password  по умолчанию для Firebird - masterkey).
Объекты класса TSQLQuery представляют собой наборы данных. В него загружается копия таблицы с сервера БД, с которой потом и осуществляется вся работа.
TSQLQuery поддерживает два принципиально разных способа доступа к данными: навигационный, который заключается в обработке каждой отдельной(текущей) записи(строки) таблицы; и реляционный, основанный на обработке сразу группы записей, посредствам SQL-запросов.

***********
Не расчитывая на студентов – киндервундеров, а ориентируясь на середняков можно сделать такой план работы
1 пара – создать и заполнить БД (20-40 мин); + начинаем писать программу – задача на оставшиеся полпары – правильно настроится на БД и получить из нее те данные что уже забиты.
2 пара – дорабатываем программу функциями (кнопками) – вставить/удалить/исправить
3 пара – дорабатываем программу диалоговым окном «Настройки» где можем указывать параметры подключения к БД
**********
Увеличим размеры формы

Добавим на форму визуальные компоненты TDBGrid – сетка таблицы и TDBNavigator – панелька с кнопками навигации по таблице – эти компоненты первый и последний в разделе DataControls

Свяжем компоненты :  у DBGrid1 и DBNavigator1  установим для свойства DataSource значение DataSource1. 
<блок теории>
Реляционный способ доступа к данным
Сначала познакомимся с реляционным способом доступа к данным, в частности рассмотрим способы выполнения SQL запросов. SQL запросы можно разделить на две группы: возвращающие и не возвращающие результат.
(SQLStructured Query Languagе – структурированный язык запросов   (к БД) команд в нем немного – select, insert,update,delete – больше нам не надо)
( select <поле1>,<поле2>…. from <таблица>    или * если нужно все поля)
Например, запрос
Select * from anketa;
подразумевает запись в набор данных копии таблицы anketa. Для его выполнения нужно использовать код:
SQLQuery1.Close;
SQLQuery1.SQL.Clear;
SQLQuery1.SQL.Add(‘Select * from anketa');
SQLQuery1.Open;
Мы сначала закрываем набор данных SQLQuery1, вызывая его метод Close (Аналогичного результата можно добиться установив свойство Active в false). Если набор закрыт, его связь с базой данных разорвана. Затем мы очищаем свойство SQL с помощью метода Clear. С помощью метода Add записываем в него текст нового запроса. Исполняется запрос при выполнении команды Open, которая переводит набор данных SQLQuery1 в открытый режим и записывает в него результаты выполнения SQL запроса.
Если SQL запрос не подразумевает возврата таблиц данных (запросы INSERT и UPDATE), необходимо воспользоваться альтернативным способом его выполнения:
SQLQuery1.Close;
SQLQuery1.SQL.Clear;
SQLQuery1.SQL.Add('INSERT INTO anketa (N, Family, Name, Info)
           VALUES('+#39+edit1.text+#39+', '+#39+ edit2.text+#39+', '+#39+ edit3.text+#39+')');
SQLQuery1.ExecSQL;    
При этом, при попытке перевести набор данных в открытый режим (выполнить SQLQuery1.Open;) возникнет ошибка. Для ее устранения нужно либо записать в свойство SQL новый запрос, возвращающий таблицу, так показано ниже:
SQLQuery1.Close;
SQLQuery1.SQL.Clear;
SQLQuery1.SQL.Add('INSERT INTO anketa (N, Family, Name, Info)
           VALUES('+#39+edit1.text+#39+', '+#39+ edit2.text+#39+', '+#39+ edit3.text+#39+')');
SQLQuery1.SQL.Text:='SELECT * from  anketa';
SQLQuery1.Open;
Либо создать и использовать для таких SQL запросов отдельный набор данных (SQLQuery2), который никогда не переводить в открытый режим.
<Практика>
Подключение и отключение от базы данных в Lazarus
Будем подключаться к удаленной базе данных не сразу, а после получения явной команды от пользователя (щелчка по соответствующей кнопке), поэтому установим в инспекторе объектов свойство Сonnected компонента IBConnectiom1 и свойства Active компонент TSQLTransaction и TSQLQuery в false.
Создадим на форме кнопку «Подключиться». В обработчике нажатия напишем:
procedure TForm1.Button1Click(Sender: TObject);
begin
  try
    IBConnection1.Connected:=true;
  except
    ShowMessage(' Не могу подключиться к базе данных');
  exit;
  end;
  try
    SQLTransaction1.Active:=true;
  except
    ShowMessage(' Не могу создать транзакцию');
  exit;
  end;
  try
    SQLQuery1.Active:=false;
    SQLQuery1.SQL.Clear;
    SQLQuery1.sql.add('SELECT * from  anketa');
    SQLQuery1.Open;
  except
    ShowMessage(' Ошибка при выполнении SQL запроса.');
  exit;
  end;
end;
Таким образом, сначала производится попытка подключения к FireBird базе, если она прошла успешно, создается новая транзакция, после чего при активации объекта SQLQuery1 выполняется SQL запрос к базе данных, выбирающей все строки из таблицы.
При отключении от базы данных действуем в обратном порядке. Зададим код отключения в обработчике события OnDestroy формы
procedure TForm1.FormDestroy(Sender: TObject);
begin
  SQLQuery1.Active:=false;
  SQLTransaction1.Commit;  - при этом собственно происходит запись в файл БД
  IBConnection1.Connected:=false;
end;

********
Если студент сделал все правильно, то он должен продемонстрировать следующее:
До:


Нажимает кнопку «подключить»

И в сетке таблицы появляются данные.
********
Навигационный способ доступа к данным
Навигационный способ подразумевает последовательную работу с записями(строками) таблицы, содержащейся в наборе данных. На навигационном способе доступа основана работа визуальных компонент из вкладки «Data Controls». Разместим на нашей форме компоненты TDBGrid, TDBNavigator и три компонента TDBMemo. И установим в их свойствах DataSource ссылку на DataSource1. В свойства DataField объектов DBMemo1, DBMemo2, DBMemo3 запишем description, text и keywords соответственно. (Напоминаю, что description, text и keywords – это название полей(колонок) в таблице myArtTable.) Поскольку наш набор данных первоначально находится в закрытом состоянии (Action=false), Lazarus будет выдавать предупреждение при попытке ввода названий полей. Не обращайте внимания - это нормально.
Запустите программу и нажмите кнопу «Подключиться…». После подключения к базе данных полученная с сервера таблица будет отображаться в объекте DBGrid1. Стрелочкой слева обозначена текущая запись. С помощью кнопок панели DBNavigator1 можно перемещаться по строкам таблицы. Вы также можете редактировать записи, однако после закрытия программы все сделанные изменения сбросятся. Для их сохранения в базу необходимо вызвать метод ApplyUpdates:
SQLQuery1.ApplyUpdates;
Приведу методы класса TSQLQuery, предназначенные для навигации по базе:
  • TSQLQuery.Next – перейти на запись вперед
  • TSQLQuery.Prior – перейти на запись назад
  • TSQLQuery.First – перейти на первую запись
  • TSQLQuery.Last – перейти на последнюю запись
  • TSQLQuery.Insert – добавить новую запись
  • TSQLQuery.Delete – удалить запись
  • TSQLQuery.Edit – перевести набор данных в режим редактирования
  • TSQLQuery.Post – сохранить сделанные изменения в набор данных
  • TSQLQuery.Refresh – обновить таблицу
Для того чтобы получить значения какого-нибудь поля записи, можно воспользоваться методом FieldByName(fn:string), где fn – название поля (колонки) таблицы. Этот же метод можно использовать для записи новых данных в таблицу. Формат чтения/записи указывается с помощью свойств AsString, AsInteger, AsFloat, AsDataTime, … Например, чтобы записать текущее значения поля id в Label, можно воспользоваться кодом:
Label1.caption:=SQLQuery1.FieldByName(‘id’).AsString;
Приведем также пример редактирования текущей строки таблицы
SQLQuery1.Edit;
SQLQuery1.FieldByName(‘keywords’).AsString:=’Lazarus жжот’;
SQLQuery1.FieldByName(‘text’).AsString:=’Новый текст’;
SQLQuery1.Post;
SQLQuery1.ApplyUpdates;
Стоит отметить, что не каждый набор данных можно редактировать навигационным способом. Чтобы получить в результате SQL запроса редактируемый набор (то есть такой, что внесенные изменения можно было сохранить в базу данных), необходимо выполнение следующих условий:
  • данные отбираются только из одной таблицы;
  • таблица допускает модификацию;
  • в запросе не используется DISTINCT и статические функции;
  • в запросе не применяются соединения таблиц;
  • в запросе отсутствуют подзапросы и вложенные запросы;
  • не используется группирование данных;
  • сортировка применяется только к индексным полям;
Использование транзакций и TSQLTransaction в Lazarus
Вообще механизм транзакции необходим для сохранения целостности базы данных. Допустим, для внесения актуальных данных в базу Вам необходимо записать в разные таблицы большое количество информации. Если в процессе записи выключится электричество, то часть таблиц будут содержать актуальную информацию, а часть старую. В результате база данных окажется испорченной. Избежать этого позволяет механизм транзакций. Если все операции записи завершились успешно, транзакция считается успешной и все изменения в таблицах базы считаются подтвержденными. Если же хотя бы одна операция записи не выполнена, транзакция считается неудачной и таблицы базы данных возвращаются к состоянию, которое они имели до начала транзакции.
Для работы с транзакциями в Lazarus добавлен компонент TSQLTransaction. Однако, в настоящее время он не работает с MySQL базами данных. TSQLTransaction автоматически переходит в активное состояние при открытии набора данных (TSQLQuery) и закрывается при его закрытии. Для явного подтверждения успешности транзакции можно использовать метод TSQLTransaction.Commit. Вызывать его следует сразу после TSQLQuerty.ApplyUpdates; Для отката транзакции можно использовать метод TSQLTransaction.Rollback.