- •Введение
- •Содержание
- •1. Файловые системы
- •История развития
- •Файловые системы, принципы построения
- •Работа с типизированным файлом
- •Недостатки файловых систем
- •Задание
- •Реляционная таблица
- •Определение домена
- •Создание таблиц в среде Microsoft Access
- •Задание
- •Реляционные ключи
- •Связь между таблицами
- •Обеспечение целостности данных
- •Построение схемы данных средствами Microsoft Access
- •Мастер подстановок
- •Задание
- •Концепция ER-модели
- •Задание
- •Первая нормальная форма (1NF)
- •Вторая нормальная форма (2NF)
- •Третья нормальная форма (3NF)
- •Нормальная форма Бойса-Кодда (BCNF)
- •Четвёртая нормальная форма (4NF)
- •Пятая нормальная форма (5NF)
- •Задание
- •Выборка значений из таблиц – SELECT
- •Порядок сортировки – ORDER BY
- •Ограничение набора данных – WHERE
- •Предикат существования EXISTS
- •Агрегатные функции
- •Группировка данных – Group By
- •Псевдонимы столбцов
- •Псевдонимы таблиц
- •Объединение нескольких таблиц
- •Построение запросов в среде Microsoft Access
- •Задание
- •Вставка новой записи – INSERT
- •Редактирование данных – UPDATE
- •Удаление записей – DELETE
- •Задание
- •Основные типы данных SQL-92
- •Язык определения данных – DDL
- •Задание
- •Подготовка отчёта в среде Access
- •Задание
- •3-х уровневая архитектура ANSI-SPARC
- •Создание форм для ввода данных в Microsoft Access
- •Задание
- •Строка соединения ADO
- •Соединение с хранилищем данных, компонент TADOConnection
- •Установка соединения
- •Пример соединения без регистрации пользователя
- •Информирование о БД
- •Задание
- •Базовый класс доступа к данным TDataSet
- •Открытие и закрытие набора данных
- •Обновление набора данных
- •Перемещение по набору данных
- •Создание закладок и переход к закладке
- •Редактирование записей в наборе
- •Фильтрация набора данных
- •Организация поиска данных
- •Взаимодействие с элементами управления данными
- •Задание
- •Поле таблицы – класс TField
- •Классификация полей по функциональному назначению
- •Классификация полей по типу обслуживаемых данных
- •Обращение к отдельному объекту-полю
- •Задание
- •Поля подстановки
- •Вычисляемые поля
- •Организация отношения главная-подчинённая таблица
- •Задание
- •Поля BLOB
- •Задание
- •Источник данных – компонент TDataSource
- •Общие черты компонентов отображения данных
- •Сетка базы данных – компонент TDBGrid
- •Статический текст – компонент TDBText
- •Строка ввода БД – компонент TDBEdit
- •Многострочный текстовый редактор БД – TDBMemo
- •Изображение БД – компонент TDBImage
- •Список БД – TDBListBox
- •Комбинированный список БД – TDBComboBox
- •Флажок БД – TDBCheckBox
- •Радиогруппа БД – TDBRadioGroup
- •Компонент – TDBCtrlGrid
- •Навигатор – TDBNavigator
- •Задание
- •Создание базы данных
- •Удаление базы данных
- •Создание таблиц
- •Пример создания таблиц средствами Transact SQL
- •Создание представлений
- •Задание
- •Определение и использование переменных
- •Операторы управления Transact-SQL
- •Базовые функции Transact-SQL
- •Хранимые процедуры
- •Триггеры
- •Задание
- •Запрос TADOQuery
- •Хранимая процедура TADOStoredProc
- •Транзакции и их изоляция
- •Управление транзакциями и компонент TADOConnection
- •Задание
- •Построение простейшего документа XML
- •Атрибуты
- •Определение документа DTD
- •Задание
92
Поля BLOB
Класс TBlobField реализован для обеспечения работы с двоичными большими объектами (binary large object, BLOB) переменной длины. Поля этого типа и его производные представляют собой универсальное хранилище большого объёма разнотипной информации. Поля BLOB широко представлены практически во всех СУБД. Например: в таблицах Paradox к таковым относятся большие текстовые поля (Memo), поля форматированного тек-
ста (FormattedMemo), графическое поле (Graphic).
Если рассуждать о специализации BLOB полей, то стоит обратить внимание на свойство:
property BlobType: TBlobType;
где
type TBlobType = ftBlob..ftOraClob;
Тип данных TBlobType это всего-навсего подмножество TFieldType. Значения, которые может принимать это тип данных, вы можете просмотреть в справочной системе. Хотя свойство BlobType доступно как для чтения, так и для записи, но если возникла необходимость, поменять тип поля целесообразнее вызвать метод:
Почти все методы BLOB поля нацелены на решение вопросов чтения или записи данных. Для загрузки данных в поле предназначены два метода:
procedure LoadFromFile(const FileName: string); procedure LoadFromStream(Stream: TStream);
В первом случае требуется передать имя графического файла FileName. Реализация второго метода несколько сложнее, в нём работа осуществляется с областью памяти – пото-
ком Stream.
Для выгрузки данных из поля реализованы два симметричных метода с аналогичными параметрами:
procedure SaveToFile(const FileName: string); procedure SaveToStream(Stream: TStream);
Для копирования данных из другого BLOB-поля определена процедура.
procedure Assign(Source: TPersistent);
Здесь в качестве параметра передаётся источник данных – Source. В роли источника данных могут выступать: другие BLOB поля, набор строк TStrings, графические объекты, например TBitmap.
Факт изменения данных внутри поля можно проверить, просмотрев свойство:
property Modified: Boolean;
Значение True является признаком, что поле изменялось.
Разработаем небольшой пример, демонстрирующий работу с BLOB полем. Задача заключается в следующем: нам требуется научить приложение сохранять в таблице растровую картинку и имя файла, соответствующего этому изображению. Начнём с проектирования структуры таблицы. Для решения поставленной задачи нам достаточно определить три поля: первичный ключ PICTURE_KEY, поле PICTUREBLOB для хранения графики и текстовое поле для хранения имени файла PICTURENAME. Воспользуемся услугами СУБД Microsoft Access 2007 и создадим в ней файл БД с именем blobdemo.accdb. База данных будет содержать единственную таблицу PICTURETABLE (см. рис 19.9) с описанными выше характеристиками.
© 2011 г. Д.Л. Осипов
93
Рисунок 15.1. Структура таблицы для работы с полем BLOB
Приступаем к работе в Delphi. Создаём новый проект и размещаем на главной форме следующий перечень компонентов: таблица – ADOTable1, диалог доступа к файлам в стиле Vista – FileOpenDialog1, объект Image1 – для отображения рисунков, метку для отображения названия файла – StaticText1, и семь кнопок класса TSpeedButton. Первые четыре кнопки (см. внешний вид формы на рисунке 15.2) предназначены для перемещения по записям внутри таблицы. Назовём их следующим образом: btnFirst – для перемещения на самую первую запись, btnPrior – предыдущая запись, btnNext – следующая запись, btnLast – последняя запись. Кроме имён кнопок потребуется изменить значения их свойств tag. Для btnFirst – 0, btnPrior – 1, btnNaxt – 2, btnLast – 3. И осталось три кнопки, отвечающие непосредственно за редактирование данных в таблице: btnAppend – добавляет новую запись в конец набора, btnEdit – редактирует текущую запись и btnDelete – отвечает за удаление.
Рисунок 15.2. Внешний вид формы для работы с BLOB-полем
Сохраните проект в том же каталоге где и расположен файл blobdemo.accdb. Главную форму проекта по традиции назовём frmMain.dfm, соответствующий ей модуль –
main.pas, а весь проект – blobdemo.dpr.
Настройте строку соединения для компонента ADOTable1.
В секции частных объявлений опишем заголовки двух процедур SetData() и GetData(). Процедура SetData() предназначена для организации загрузки файла рисунка в BLOB поле. Для этого вызывается диалог открытия изображения. Если пользователь выберет файл и при этом таблица находится в режиме вставки (dsInsert) или редактирования (dsEdit) оба поля записи будут заполнены соответствующими данными.
procedure TfrmMain.SetData; begin
if (FileOpenDialog1.Execute) and
((ADOTable1.State=dsInsert) or (ADOTable1.State=dsEdit)) then begin
(ADOTable1.FieldByName('PICTUREBLOB') as TBlobField).LoadFromFile(FileOpenDialog1.FileName); ADOTable1.FieldByName('PICTURENAME').AsString:=
ExtractFileName(FileOpenDialog1.FileName);
© 2011 г. Д.Л. Осипов
94
end; end;
Процедура GetData() предназначена для извлечения данных из текстового и BLOB поля. Название файла загружается в Caption компонента StaticText1. Если поле Image не пусто, то мы создаём поток M:TMemoryStream, загружаем в него данные из поля, и передаём их в компонент Image1. Обращаю внимание, на то что, перед передачей данных из потока его следует установить на нулевую позицию. В заключении освобождаем ресурсы, занимаемые потоком, вызвав метод Free().
procedure TfrmMain.GetData; var M : TMemoryStream; begin
with ADOTable1 do begin
StaticText1.Caption:=FieldByName('PICTURENAME').AsString;
if (FieldByName('PICTUREBLOB') as TBlobField).IsNull=False then begin
M:=TMemoryStream.Create;
(FieldByName('PICTUREBLOB') as TBlobField).SaveToStream(M); M.Position:=0;
Image1.Picture.Bitmap.LoadFromStream(M);
M.Free;
end else Image1.Picture.Bitmap.FreeImage; end;
end;
После того, как были созданы ключевые процедуры чтения и записи данных, переходим к описанию основных событий. Первое из них – событие OnCreate() главной формы проекта. В нём мы осуществим подключение компонента ADOTable1 к базе данных, определим параметры диалога открытия изображений.
procedure TfrmMain.FormCreate(Sender: TObject); var s:string;
FT:TFileTypeItem;
const db='\blobdemo.accdb'; begin
{подключаемся к базе данных} s:=ExtractFilePath(Application.ExeName)+db; if FileAge(s)>0 then
begin
ADOTable1.ConnectionString:='Provider=Microsoft.ACE.OLEDB.12.0; Data Source='+s+';Persist Security In-
fo=False';
ADOTable1.TableName:='PICTURETABLE';
ADOTable1.Open;
GetData;
{настраиваем файловый диалог в стиле Vista} FT:=FileOpenDialog1.FileTypes.Add; FT.FileMask:='*.bmp'; FT.DisplayName:='Растровый файл';
end else begin
Application.MessageBox(pChar('Не найден файл'+#13+S),'Ошибка',MB_OK);
Application.Terminate; end;
end;
Выберите кнопку btnFirst, отвечающую за перевод курсора на самую первую запись в таблице и опишите её обработчик события OnClick(). Особенность события в том, что оно будет применяться для всех четырёх кнопок перемещения. Если помните, кнопки перемещения по записям таблицы различаются свойством tag, btnFirst – 0, btnPrior – 1,
© 2011 г. Д.Л. Осипов
95
btnNext – 2, btnLast – 3. Анализируя свойство tag в селекторе Case мы вызываем соответствующий метод таблицы.
procedure TfrmMain.btnFirstClick(Sender: TObject); begin
with ADOTable1 do
Begin
{перемещаем курсор в соответствии со значением свойства tag кнопок перемещения по записям}
case (sender as TComponent).Tag of
0:First; //на первую запись
1:Prior; //на предыдущую запись
2:Next; //на следующую запись
3:Last; //на последнюю запись набора данных
end;
GetData;//получаем данные из таблицы
{с помощью методов BOF и EOF проверяем местоположение текущей записи} btnFirst.Enabled:=NOT(BOF);{кнопка отключается,
если курсор на первой записи}
btnPrior.Enabled:=NOT(BOF); btnNext.Enabled:=NOT(EOF);{кнопка отключается,
если курсор на последней записи}
btnLast.Enabled:=NOT(EOF);
end;
end;
В заключении нам осталось описать действия добавления, редактирования и удаления записи.
procedure TfrmMain.btnAppendClick(Sender: TObject);//добавление begin
ADOTable1.Append; {добавление новой записи в конец набора} SetData; {вызов выбора изображения}
GetData; {передаём данные в компонент Image1 и StaticText1} end;
procedure TfrmMain.btnEditClick(Sender: TObject);//редактирование begin
ADOTable1.Edit;{перевод таблицы в режим редактирования} SetData;
GetData; end;
procedure TfrmMain.btnDeleteClick(Sender: TObject);//удаление begin
if MessageBox(frmMain.Handle, pWideChar('Удалить запись?'), pWideChar('Удаление'),
MB_YESNO + MB_ICONQUESTION)=idYes then
begin |
{удаление записи} |
ADOTable1.Delete; |
|
Image1.Picture.Bitmap.FreeImage; |
{освобождаем ресурс картинки} |
StaticText1.Caption:=''; |
{очищаем заголовок метки} |
GetData; |
|
end; |
|
end; |
|
© 2011 г. Д.Л. Осипов