- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Мир InterBase. Архитектура, администрирование и разработка приложений баз данных в InterBase/FireBird/Yaffil - А Ковязин
Шрифт:
Интервал:
Закладка:
v[2] = FieldByName( LQ2 ) AsString,
QryArrField Fields[0] SetArrayValue(v);
QUpdate Params ByName[ LQ ] AsQuad :=
QryArrField.Fields[0] AsQuad;
end;
QryArrField Close;
end;
Теперь все становится совершенно очевидным Поскотьку свойство QiyAnField KindUpdate равно ukModify, то QiyArrField выполняет запрос при изменении записи в AnayDataSet а поскольку свойство QiyArrField ExecuteOider равно eoBeforeDefault, то запрос (QiyArrField SQL) выполняется до того, как AirayDataSet выполнит свой собственный UpdateSQL В обработчике QryArrField AfterExecute мы всего лишь получаем заново все текущие элементы массива из базы данных, подменяем два из них новыми значениями, которые указал пользователь, и задаем значение параметра для ArrayDataSet.UpdateSQL Это означает что при выполнении ArrayDataSet.UpdateSQL формально будут обновлены все пять элементов массива но фактически изменены значения тотько двух элементов, которые изменил пользователь в TDBGrid.
Как видите работа с массивами достаточно проста поскотьку все основные сложности решают компоненты FIBPlus Хотелось бы также рассмотреть еще один специализированный компонент, входящий в FIBPlus Пример DemoArray демонстрирует работу с TDataSetContamei, использованным для синхронизации значений двух TpFIBDataSet, редактирующих наше апау-поле (рис 2 64)
Рис 2.64. Использование TDatabetContamer
Компонент DataSetContamerl помещен вместе с Database и Transaction на DataModule в нашем приложении Оба компонента AnayDataSet из разных форм нашего приложения ссылаются на DataSetContamerl при помощи свойства Contamei (рис 2 65)
Рис 2.65. Подключение компонентов TpFIBDataSet к DataSetContamerl
Компонент TDataSetContamei позволяет централизованно обрабатывать события от разных компонентов TpFIBDataSet, а также (расширяя, таким образом, список стандартных событий) посылать им сообщения, при получении которых они могут производить какие-то дополнительные действия. В нашем примере DataSetContainerl имеет обработчики двух событий OnDataSetEvent и OnUserEvent
procedure TDataModule2.DataSetsContainerlDataSetEvent(DataSet:
TDataSet;
Event: TKindDataSetEvent);
var Info: string;
begin
if Event = deAfterPost then
if DataSet.Owner.Name = 'Forml' then
DataSetsContainerl.NotifyDataSets(DataSet,
'Form2.ArrayDataSet', 'JOB_TABLE_CHANGED', Info)
else
if DataSet.Owner.Name = 'Form2' then
DataSetsContainerl.NotifyDataSets(DataSet,
'Form1.ArrayDataSet', 'JOB_TABLE_CHANGED', Info);
end;
procedure TDataModule2.DataSetsContainerlUserEvent(Sender:
TObject;
Receiver: TDataSet; const EventName: String; var Info:
String) ;
begin
if EventName = 'JOB_TABLE_CHANGED' then begin
with TpFIBDataSet(Sender) do
if (not CachedUpdates) and
(not TpFIBDataSet(Receiver).CachedUpdates) then
if
TpFIBDataSet(Receiver).Locate('JOB_CODE;JOB_GRADE;JOB_COUNTRY', varArrayOf([
FieldByNamet'JOB_CODE').AsString,
FieldByName('JOB_GRADE').AsString,
FieldByName('JOB_COUNTRY').AsString
]), []) then TpFIBDataSet(Receiver) Refresh
end;
end;
Смысл действий сводится к следующему: после изменения записи в одном из наших компонентов ArrayDataSet происходит событие AfterPost. Поскольку DataSetContainerl перехватывает все события у подчиненных компонентов, то срабатывает обработчик OnDataSetEvent. Параметр Event равен deAfterPost, а параметр DataSet ссылается на тот компонент, в котором произошло изменение записи. При помощи вызова метода NotifyDataSets DataSetContainerl посылает сообщение оставшемуся компоненту ArrayDataSet о том, что произошло изменение записи. Поскольку оба компонента на самом деле редактируют одну и ту же таблицу, то желательно синхронизировать изменения. Синхронизация происходит в обработчике события OnUserEvent, то есть при получении "извещения" об изменении какого-либо из ArrayDataSet.
Если получено сообщение "JOB_TABLE_CHANGED" и ни в одном из наших двух ArrayDataSet не включен режим CachedUpdates (в этом случае Refresh просто ничего не даст), то мы позиционируемся на соответствующую запись и вызываем для нее метод Refresh, обновив, таким образом, запись в одном ArrayDataSet после того, как она была изменена в другом ArrayDataSet.
Данная технология является совершенно уникальной: использование DataSetContainer позволяет делать чрезвычайно гибкие и в то же время прозрачные схемы обработки и синхронизации данных в нескольких компонентах TpFIBDataSet.
Работа с BLOB-полями
Достаточно часто желательно хранить в базе данных разнообразные неструктурированные данные: изображения, OLE-объекты, звук и т. д. Специально для этих целей существует специальный тип данных - BLOB Продемонстрируем использование BLOB-полей на примере простого приложения (см. рис. 2.66), использующего следующую таблицу:
CREATE TABLE BIOLIFE (
ID INTEGER NOT NULL,
CATEGORY VARCKAR (15) character set WIN1251 collate
WIN1251,
COMMON_NAME VARCHAR (30) character set WIN1251 collate
WIN1251,
SPECIES_NAME VARCHAR (40) character set WIN1251 collate
WIN1251,
LENGTH_CM_ DOUBLE PRECISION,
LENGTH_IN DOUBLE PRECISION,
NOTES BLOB sub_type 1 segment size 80,
GRAPHIC BLOB sub_type 0 segment size 80);
Для вывода изображений, сохраненных в поле GRAPHIC, мы будем использовать стандартный компонент DBIMagel: TDBImage. Очевидно также, что запросы при работе с BLOB-полями ничем не отличаются от запросов со стандартными типами полей:
SelectSQL:
SELECT * FROM BIOLIFE
UpdateSQL:
UPDATE BIOLIFE Set
ID=?NEW_ID,
CATEGORY=?NEW_CATEGORY,
COMMON_NAME=?NEW_COMMON_NAME,
SPECIES_NAME=?NEW_SPECIES_NAME,
LENGTH__CM_=?NEW_LENGTH_CM_,
LENGTH_IN=?NEW_LENGTH_IN,
NOTES=?NEW_NOTES,
GRAPHIC=?NEW_GRAPHIC
WHERE ID=?OLD_ID
Рис 2.66. Внешний вид формы приложения для работы с BLOB-полями
InsertSQL:
INSERT INTO BIOLIFE(
ID,
CATEGORY,
COMMON_NAME,
SPECIES_NAME,
LENGTH__CM_,
LENGTH_IN,
NOTES,
GRAPHIC
)
VALUES (
?NEW_ID,
?NEW_CATEGORY,
?NEW_COMMON_NAME,
?NEW_SPECIES_NAME,
?NEW_LENGTH_CM_,
?NEW_LENGTH_IN,
?NEW_NOTES ,
?NEW_GRAPHIC
)
DeleteSQL:
DELETE FROM BIOLIFE
WHERE ID=?OLD_ID
RefreshSQL:
SELECT * FROM BIOLIFE
WHERE
ID=?OLD_ID
Единственным отличием от обычных типов данных является то, что для присвоения значения BLOB-параметру необходимо использовать потоки (специализированные потомки стандартного класса TStream). Например, если мы хотим сохранить в нашем поле изображение из внешнего файла, то мы можем написать следующий обработчик нажатия на кнопку:
procedure TMainForm.OpenBClick(Sender: ТОbjесt);
var S. TStream;
FileS: TFileStream;
begin
if not OpenD.Execute then exit;
pFIBDataSetl.Edit;
S : =
pFIBDataSetl.CreateBlobStream(pFIBDataSetl.FieldByName('GRAPHIC') , bmReadWrite);
try
FileS := TFiIeStream.Create(OpenD.FileName, fmOpenRead);
S.CopyFrom(FileS, FileS.Size);
finally
FileS.Free;
S.Free;
pFIBDataSetl.Post;
end;
end;
Обратите внимание на важный момент - перед тем как присваивать значение BLOB-параметру, необходимо перевести pFIBDataSet в состояние редактирования данных. В данном случае это делается безусловным вызовом метода Edit. Вызов метода CreateBlobStream создает экземпляр специального внутреннего класса TFIBDSBlobStream. Скорее всего, вам не придется использовать этот класс напрямую. В нашем примере он нужен только для обмена данными между BLOB-параметром и потоком, который читает данные из файла с изображением. Параметр bmReadWrite означает, что мы собираемся изменять содержимое параметра. Поток S напрямую связан с BLOB-параметром, поэтому, копируя данные из файла (FileS) в поток S, мы фактически присваиваем значение параметру. Остается только сохранить изменения вызовом метода Post Аналогичным образом мы можем сохранить значение BLOB-поля в некоторый внешний файл:
procedure TMainForm.SaveBClick(Sender: TObject);
var S: TStream;
FileS: TFiIeStream;
begin
if not SaveD.Execute then exit;
if not pFIBDatasetl.FieldByName('GRAPHIC').IsNull then begin
S : =
pFIBDatasetl.CreaceBlobStream(pFIBDatasetl.FieldByName('GRAPHIC '), bmRead);
try
if FileExists(SaveD.FileName) then
FileS := TFileStream.Create(SaveD.FileName, fmOpenWrite)
else
FileS := TFileStream.Create(SaveD.FileName, fmCreate);
FileS.CopyFrom(S, S.Size);
finally
S.Free;
FileS.Free;
end;
end;
end;
Обратите внимание, что в этой процедуре мы используем параметр bmRead при создании потока S. Очевидно, что для сохранения содержимого BLOB-поля в файл нам не нужно изменять само поле, поэтому мы создаем поток только для чтения. Еще более простым способом мы можем очистить содержимое BLOB-поля:
procedure TMainForm.ButtonlClick(Sender: TObject);
begin
pFIBDataSetl .Edit;
pFIBDataSetl.FieldByName('GRAPHIC').Clear;
pFIBDataSetl.Post;
end;
В этом случае даже не требуется создавать какие-либо потоки. Иногда также нужно знать, является ли BLOB-поле пустым или нет. При использовании визуальных компонентов типа TDBImage мы не можем быть в этом уверены. Согласитесь, что никто не мешает нам "нарисовать" пустую картинку и сохранить ее в BLOB-поле В этом случае мы не сможем отличить "на глаз": есть ли какое-то изображение в BLOB-поле или нет. Однако мы можем написать обработчик события OnDataChange компонента DataSourcel: TDataSource:
procedure TMainForm.DataSourcelDataChange(Sender: TObject;
Field: TField) ;
begin
CheckBoxl.Checked :=
pFIBDataSetl.FieldByName('GRAPHIC').IsNull;
end;
Это событие вызывается, в частности, при навигации по DBGridl; таким образом, мы всегда можем узнать, является ли текущее поле пустым или нет.
Если вы используете TpFIBQuery для работы с BLOB-полями, то общий принцип остается тем же - необходимо использовать потоки, однако, в отличие от TpFIBDataSet, вам не потребуется создавать какие-то специальные потоки. Например, мы можем написать следующую процедуру, которая сохранит в файлы все изображения из нашей таблицы:
pFIBQuery.SQL: SELECT * FROM BIOLIFE
procedure TMainForm.Button2Click(Sender: TObject);
var SaveFile: TFileStream;
Index: Integer;
begin
with pFIBQueryl do begin ExecQuery;
Index := 1;
while not Eof do begin
SaveFile := TFileStream.Create(IntToStr(Index) + '.bmp',
fmCreate);
FN('GRAPHIC').SaveToStream(SaveFile);
Next;
inc(Index);

