- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Мир InterBase. Архитектура, администрирование и разработка приложений баз данных в InterBase/FireBird/Yaffil - А Ковязин
Шрифт:
Интервал:
Закладка:
INSERT INTO "Categories"(
"Id" ,
" Name" ,
"GoodsCount"
)
VALUES(
:"Id",
:"Name",
:"GoodsCount"
)
Puc 2.22. Редактор компонента TpFIBDataSet, предназначенный для генерации модифицирующих запросов
Обратите внимание также на запрос для свойства RefreshSQL:
select * from "Categories"
WHERE
(
"Categories"."Id" = :"OLD_Id"
)
Это такой же выбирающий запрос, как и запрос в свойстве SelectSQL, но возвращать он должен только одну запись - текущую Теперь, после создания всех запросов, когда пользователь будет редактировать запись в CategoriesGrid, CategonesDataSet автоматически заполнит значения параметров : "Id", . "Name" и т д., теми значениями полей, которые наберет пользователь. После выполнения метода Post (который, в частности, вызывается при нажатии клавиши Enter в CategonesGnd) CategoriesDataSet выполнит соответствующий модифицирующий запрос После редактирования записи будет выполнен запрос из свойства UpdateSQL, при вставке новой записи - из InsertSQL, а при удалении записи - из DeleteSQL После выполнения любого модифицирующего запроса (кроме удаления) CategoriesDataSet автоматически выполняет запрос из RefreshSQL, подставляя в качестве условия текущие значения параметров. Это позволяет "узнать" значения всех полей текущей записи, если они были изменены при помощи триггеров базы данных.
Несколько слов о специальных префиксах для параметров, которые используются в FIBPlus.
Префикс "OLD_" фактически означает текущее значение одноименного поля или же предыдущее значение поля Термин "предыдущее значение" имеет смысл в запросе на удаление. Во всех остальных случаях, когда нужны актуальные значения полей, можно обходиться без данного префикса.
Префикс "NEW_" означает новое значение поля и фактически имеет смысл только в запросах на изменение и вставку. Однако новые значения полей в этих ситуациях также являются и текущими, а значит, префикс "NEW_" можно опускать
Существует также специальный префикс "MAS_", но мы доберемся до него несколько позже.
Поскольку мы сгенерировали все необходимые модифицирующие запросы, то уже можем запустить наше приложение, добавить пару категорий, изменить их названия и даже целиком удалить их.
Тем не менее генерация модифицирующих запросов в design-time не всегда удобна FIBPIus позволяет разработчику автоматически генерировать нужные запросы во время работы приложения, основываясь на запросе из свойства SelectSQL Для этого нужно использовать свойство AutoUpdateOptions (рис 223).
Рис 2.23. Комплексное свойство AutoUpdateOptions
Необходимо "включить" ключ "AutoReWriteSqls", указать ключевое поле, которое будет использовано в условиях WHERE (в нашем случае, это поле "Id") и указать название модифицируемой таблицы ("Categories"), поскольку в реальности запросы могут быть многотабличными. Теперь свойства InsertSQL, DeleteSQL, UpdateSQL и RefreshSQL будут генерироваться автоматически при открытии CategonesDataSet. To есть фактически мы имеем генератор запросов в run-time, что бывает очень удобно.
Есть еще один момент, связанный с генерацией модифицирующих запросов Например, если мы редактируем только название категории, то после нажатия на Entei на сервер будет отправлен запрос, в котором изменены два поля и Name и GoodsCount Фактически же мы изменяли только одно поле - "Name".В итоге если запись таблицы содержит значительный объем данных (например, длинные строковые поля), то при малейшем исправлении даже одного поля на сервер будут "уходить" все данные. При многопользовательской работе это создаст дополнительный лишний трафик Данной ситуации можно избежать но для этого необходимо, чтобы приложение выполняло 6oлee эффективные изменяющие запросы, например запрос:
UPDATE "Categories" SET
"Name" = ."Name"
WHERE
"Id" = :"OLD_Id"
в котором, как вы видите, участвует только то поле, значение которого действительно было изменено. Такая возможность существует, если мы включим ключ UpdateOnlyModifiedFields (разумеется, этот ключ действует, только если мы используем режим генерации запросов в run-time). В случае редактирования только поля "Name" компонент CategoriesDataSet автоматически сгенерирует запрос, приведенный выше, и будет генерировать каждый раз новые запросы в зависимости от того, какие поля изменялись.
Поскольку теперь наш CategoriesDataSet стал модифицируемым, то мы можем написать обработчики событий OnClick у трех кнопок справа от CategoriesGrid:
procedure TMainForm AddCatButtonClick(Sender TObject);
begin
CategoriesDataSet Append;
end;
procedure TMainForm.EditCatButtonClick(Sender: TObject);
begin
CategoriesDataSet Edit;
end;
procedure TMainForm.DeleteCatButtonClick(Sender: TObject);
begin
if MessageDlg('Вы уверены, что хотите удалить категорию "' +
CategoriesDataSet.FieldByName('Name').AsString + '"?',
mtConfirmation,
[mbYes, mbNo], 0) = mrYes then
CategoriesDataSet.Delete;
end;
Правильный способ использования auto-increment полей в FIBPIus
В текущем состоянии наш запрос уже является редактируемым, мы можем вставлять новые записи, удалять записи существующие, а также редактировать значения полей Тем не менее пользователь должен самостоятельно указывать значение ключевого поля "Id", чтобы каждая запись была уникальной. Разумеется, мы можем переложить заботу о генерации уникальных значений на базу данных, написав соответствующий триггер, который при вставке новой записи будет автоматически получать новое уникальное значение из некоторого 1енерагора. Такой способ гарантирует уникальность значений, но не гарантирует правильность работы клиентского приложения.
Особенность использования генераторов при написании корректно работающих приложений на FIBPlus состоит в том, что мы должны получать новое значение генератора в приложении до того, как выполним запрос на вставку записи. Зачем это нужно? Дело в том, что, как уже было сказано, после выполнения любого модифицирующего запроса (кроме удаления) CategoriesDataSet автоматически выполняет запрос из RefreshSQL, подставляя в качестве условия текущие значения параметров. В нашем случае для подстановки надо использовать значение первичного ключа (поле "Id"). Если мы не получим его заранее, а будем генерировать его, используя триггер, то мы не сможем подставить значение параметра : "OLD_Id" в запрос RefreshSQL, а значит, не сможем перечитать измененную запись. Таким образом, если какие-то поля записи были изменены триггерами базы данных, то мы не увидим этих изменений, пока не переоткроем весь запрос целиком Если же мы сначала получим новое значение генератора, а потом вставим это значение наравне с остальными параметрами, то затем мы сможем использовать это же значение, чтобы "перечитать" текущую запись, и будем "в курсе" актуальных значений полей без излишних переоткрываний!
TpFIBDataSet позволяет автоматически получать и вставлять значения первичного ключа, используя генератор. Для этого нам необходимо заполнить некоторые дополнительные ключи в свойстве AutoUpdateOptions (рис. 2.24).
Нужно указать название генератора Categories_Id_GEN. Свойство WhenGetGenID может принимать три возможных значения:
wgOnNewRecord - получать значение генератора сразу после подготовки буфера для новой записи;
wgBeforePost - получать значение генератора непосредственно перед отправкой новой записи на сервер;
wgNever- не использовать механизм генерации ключевых значений.
В нашем примере мы укажем значение wgOnNewRecord, чтобы сразу видеть в CategoriesGrid те значения поля "Id", которые будут получены с сервера. Теперь мы можем запустить наше приложение и отредактировать какие-либо существующие записи и даже вставить новые записи (рис. 2.25).
Рис 2.24. Использование AutoUpdateOptions для генерации уникальных значений первичного ключа
Рис 2.25. Внешний вид "живого" запроса
Из рисунка видно, что было автоматически получено значение для поля "Id" равное 66
Разделенные транзакции: уникальная возможность избежать Deadlock. Режим AutoCommit
CategoriesDataSet позволяет автоматически подтверждать сделанные изменения, если задать свойство AutoCommit в True. Теперь после вызова метода Post компонент CategoriesDataSet будет автоматически вызывать CategonesTransaction CommitRetainmg, сохраняя сделанные пользователем изменения и не закрывая при этом сам запрос. Такой подход уже снижает вероятность Deadlock, который возможен при наличии длинных незакрытых транзакций, в контекст которых производились изменения данных.
Тем не менее, FIBPlus предлагает другую возможность, которая сводит вероятность возникновения Deadlock практически к нулю. TpFIBDataSet может работать одновременно в контексте двух транзакций. Одна длинная транзакция, в контексте которой данные только читаются, и другая короткая транзакция, в контексте которой выполняются все модифицирующие запросы.
Переименуем CategoriesTransaction в CategoriesReadTransaction и добавим еще один компонент CategoriesWriteTransaction. После этого зададим свойство UpdateTransaction у CategoriesDataSet в CategoriesWriteTransaction. Таким образом, теперь CategoriesDataSet подключен сразу к двум компонентам TpFTBTransaction (рис. 2.26).

