Эльчин Азиз Али оглы Азизов дата публикации 01-06-2001 00:00 Немного об использовании ADO в Delphi. ( часть 3 )
В прошлый раз речь шла о динамических свойствах ADO. На всякий случай напомню, что доступ к ним осуществляется через свойство TADODataSet.Properties и справка Delphi об их назначении сообщает весьма немного.
Сегодня продолжим об этом же - я хочу рассказать еще о парочке свойств, которые могут пригодиться.
Мы знаем уже, что при открытии набора данных Cursor Engine получает метаданные, которые позволяют ему посылать на сервер правильные команды при добавлении, удалении и редактировании строк. Случай, если набор данных состоит из строк какой-то одной таблицы, мы уже изучили, а что если это запрос на объединение двух (или нескольких) таблиц?
Вернемся к нашей игрушечной базе данных (см структуру во второй части). Как видите, я заранее заготовил табличку Calls - со звонками абонентов - чтобы было из чего создать запрос на объединение. Вот он, собственно запрос:
SELECT
Abonents.AbonentID AS A_AbonentID,
Abonents.AbonentName,
Calls.*
FROM
Abonents
INNER JOIN
Calls ON Abonents.AbonentID = Calls.AbonentID
Здесь небольшое пояснение - колонке AbonentID из таблицы Abonents присвоен псевдоним AbonentID_A чтобы легче было их различить - и проще было работать (дальше станет яснее).
Попробуем открыть этот запрос в нашей программке:
Мы видим список звонков абонентов с их фамилиями - все прекрасно. Видеть-то видим и можем его, например, напечатать, а что если пользователю взбредет в голову его редактировать?
Попробуем поменять номер телефона, по которому Иванов звонил 4-го апреля. Работает! Cursor Engine сам сообразил что нужно поменять таблицу Calls! Теперь поменяем фамилию Иванов на Иванова… Тоже сработало, однако пришлось нажать кнопку Refresh dbNavigator'а чтобы увидеть, это исправление для всех строк.
Смертельный номер! Сейчас попробуем удалить строку! Нажимаем значок "-" на dbNavigator'а (или Ctrl+Delete) и обновляем данные…
Что за дела! Выскакивает сообщение об ошибке… И выясняется, что Cursor Engine пытался удалить не только звонок Иванова из таблицы Calls но и самого Иванова из таблицы Abonents. Если это именно то, чего Вы ожидали, я Вас поздравляю.
А если Вы не хотели стирать самого Иванова - а только один его звонок - от 4-го апреля?
Неужели нет никакого способа указать, что удаление должно касаться только одной таблицы? Ответ - есть такой способ - динамическое свойство - 'Unique Table'
Все просто - свойству 'Unique Table' нужно присвоить имя той таблицы, над которой производятся манипуляции (удаления и исправления).
ADODataSet1.Properties['Unique Table'].Value:='Calls';
В общем-то, все про Unique Table. Но минутку, не оговорился ли я, сказав, что оно нужно не только при удалении, но и при исправлении? Ведь мы свободно могли изменять номер, по которому звонил Иванов 4-го апреля, вовсе не установив никакого «Unique Table». Согласен. А теперь представьте такую ситуацию - выяснилось, что звонок от 4-го апреля принадлежит вовсе не Иванову, а скажем Петрову?
Никаких проблем - достаточно изменить поле AbonentID в соответствующей строке с 2 на 1. Попробуем-ка… Что мы видим?
Не все в порядке. Calls.AbonentID равен 1. Но фамилия абонента в этой строке осталась прежней. Ничего, нажмем Refresh. Не помогает! Почему? Потому что Cursor Engine обновляет строку в два приема - сначала считывает строку из таблицы Abonents, используя AbonentID из таблицы Abonents (в нашем примере это первая колонка - AbonentID_A), а потом считывает строку из таблицы Calls - используя значение CallId.
Вот тут бы пригодилась возможность «подсунуть» Cursor Engine'у свою собственную команду для обновления строки чтоб заставить его считать данные используя AbonentID из таблицы Calls.
Ну естественно, раз я завел об этом речь - значит такая возможность есть - эту возможность представляет динамическое свойство 'Resync Command'.
Свойство 'Resync Command' используется совместно с 'Unique Table' - в этом свойстве задается команда, с помощью которой должна быть обновлена текущая строка, основываясь на значении колонок из таблицы, имя которой заданно свойством 'Unique Table'.
В нашем случае:
ADODataSet1.Properties['Resync Command'].Value:=
'SELECT Abonents.AbonentID AS A_AbonentID, Abonents.AbonentName, Calls.*
FROM Abonents INNER JOIN Calls ON Abonents.AbonentID = Calls.AbonentID
WHERE Calls.CallID = ?';
Это почти такая же SQL команда как и та, с помощью которой открыт наш набор данных - с тем лишь отличием, что она считывает только одну строку, ограничивая по условию WHERE Calls.CallID = ?.
Cursor Engine подставит вместо вопросительного знака текущее значение CallId и выполнит эту команду при обновлении строки.
Примечание:
Команда которую вы передаете в свойство 'Resync Command' должна возвращать только одну строку.
А что насчет добавления новой записи? Если добавить новую запись и внести новые значения только для колонок из таблицы Calls (включая Calls.AbonentID) то будет добавлена новая строка в таблицу Calls. Если при этом установлено свойства 'Resync Command' и 'Unique Table' фамилия абонента для вновь добавленного звонка тут же будет считана с сервера, по значению Calls.AbonentID.
Примечание:
Если быть абсолютно точным - значение полей для вновь добавленной записи будет считано, если свойство 'Update Resync' имеет значение adResyncInserts или adResyncAll (см вторую часть).
Если же при добавлении были внесены значения новой строки не только для таблицы Calls? Тогда Cursor Engine попытается добавить по одной записи в обе таблицы. Это у него, скорее всего, не получится - абонента то можно добавить - но для добавления в таблицу Calls в нашем примере нужно иметь значение AbonentID которое будет в тот момент не известно.
Вы видите на рисунках на форме небольшую кнопочку Button1?
По нажатию на эту кнопку устанавливаются свойства Resync Command и Unique Table - попробуйте немного поиграть, удаляя и редактируя данные до и после нажатия этой кнопки.
Примечание:
Напоследок напомню еще разок - свойства 'Resync Command' и 'Unique Table' - динамические - это значит, что их можно изменять «по ходу пьесы» непосредственно во время работы программы.
На этом пока все, успехов!
прADOлжение следует ?
Скачать пример AdoPart3.Zip (18 K)
JINX, 01 июня 2001г.
Специально для Королевства Delphi
К материалу прилагаются файлы:
[TADODataSet] [ADO]
Обсуждение материала [ 06-10-2006 03:34 ] 35 сообщений |