Примеры программирования v8: Внешняя компонента для безопасной работы с базами данных по интерфейсу ADO
Внешняя компонента для работы с базами данных по интерфейсу ADO.
Приводит типы данных, умеет работать со ссылочными типами 1С:Предприятие.
Автор статьи: romix | Редакторы: pectopatop Последняя редакция №8 от 13.10.07 | История URL: http://kb.mista.ru/article.php?id=454
Внешняя компонента для безопасной работы с базами данных по интерфейсу ADO
Ключевые слова: ADO, база, ошибка, поле, формат, adodb, connection
http://x-romix.narod.ru/2007_01_25_ADO.rar (скачивать ЛЕВОЙ кнопкой мыши, размер ~109К)
Чем лучше AdoDB.Connection?
1) Умеет работать с различными типами данных, которые можно привести к строке, числу или дате.
2) Не теряет точность для вещественных чисел
3) Умеет читать дату и время из поля соответствующего типа.
4) Содержит удобный интерфейс для обновления записей (Insert или Update в зависимости от наличия записи с указанными ключивыми полями).
5) Поддерживает параметризацию (невозможно хакнуть программу подменой закавыченных значений).
6) Умеет работать со ссылочными типами 1С:Предприятие (справочники, документы), упаковывая их в 16-символьное представление
7) Предполагается переносимость между версиями 7.7 и 8.0 (пока не работает).
Недостатки Windows-объекта ADODB.Connection
1) Существует ошибка в реализации данного объекта:
ADODB.Connection имеет свойство KeepConnection, которое подразумевает сохранение самим объектом своего
состояния подключенности (т.е. если возникают
разрывы связи, компонент должен сам переподключаться). К сожалению, как показывает практика, разрывы
связи бывают довольно часто (несколько раз в сутки,
по Ethernet). Ошибка заключается в том, что ADODB.Connection не переустанавливает связь при разрыве.
Более того, ИНОГДА, даже если вы специально после
разрыва связи выполните команды .Close и .Open, все равно ADODB.Connection не установить связь, а лишь
создаст видимость ее установления: флаг Active=true.
Но на деле, при проверке такого фиктивного соединения (например, запрос таблицы), вылетает ошибка об
отсутствии связи. Ошибка эта повторяется довольно просто:
- создайте Delphi-проект (или даже на другом языке) с использованием ADODB.Connection, таблицы и DBGrid, связанных друг с другом. Сделайте property AdoDB.Connection.LoginPrompt = false. И задайте такую строку соединения с БД, чтобы она ссылалась на базу данных по локальной сети.
- добавьте Кнопку1 на форму, и поставьте на ее нажатие код, который будет выполнять методы .Close (в Try..Except..End), затем .Open у ADODB.Connection.
- добавьте Кнопку2 на форму, поставьте на ее нажатие код, который выведет состояние свойства ADODB.Connection.Active.
- запустите программу, нажмите Кнопку1, соединение произойдет. Проверьте это, нажав Кнопка2.
- теперь специально разорвите связь между вашим компьютером, и компьютером с БД. Как умеете: или выдерните прямо сетевой шнур, или отключите соединение..
- проверьте состояние ADODB.Connection, нажав Кнопка2: оно будет все ще думать, что оно подключено к БД.
- если вы затем вновь соедините сеть, то ADODB.Connection даже ничего и не заметит. А при попытке запроса через такое "убитое" соединение будет вылезать ошибка.
Будьте внимательны! Учитывайте данную ошибку. (повторяется на версиях ADO - 2.5, 2.8)
2) Кроме того, у ADODB.Connection существует свойство, которое указывает (в секундах) через какое время, если соединение не используется, оно само разорвет связь.
Автор статьи: romix | Редакторы: pectopatop Последняя редакция №8 от 13.10.07 | История URL: http://kb.mista.ru/article.php?id=454
Внешняя компонента для безопасной работы с базами данных по интерфейсу ADO
Ключевые слова: ADO, база, ошибка, поле, формат, adodb, connection
http://x-romix.narod.ru/2007_01_25_ADO.rar (скачивать ЛЕВОЙ кнопкой мыши, размер ~109К)
Чем лучше AdoDB.Connection?
1) Умеет работать с различными типами данных, которые можно привести к строке, числу или дате.
2) Не теряет точность для вещественных чисел
3) Умеет читать дату и время из поля соответствующего типа.
4) Содержит удобный интерфейс для обновления записей (Insert или Update в зависимости от наличия записи с указанными ключивыми полями).
5) Поддерживает параметризацию (невозможно хакнуть программу подменой закавыченных значений).
6) Умеет работать со ссылочными типами 1С:Предприятие (справочники, документы), упаковывая их в 16-символьное представление
7) Предполагается переносимость между версиями 7.7 и 8.0 (пока не работает).
Недостатки Windows-объекта ADODB.Connection
1) Существует ошибка в реализации данного объекта:
ADODB.Connection имеет свойство KeepConnection, которое подразумевает сохранение самим объектом своего
состояния подключенности (т.е. если возникают
разрывы связи, компонент должен сам переподключаться). К сожалению, как показывает практика, разрывы
связи бывают довольно часто (несколько раз в сутки,
по Ethernet). Ошибка заключается в том, что ADODB.Connection не переустанавливает связь при разрыве.
Более того, ИНОГДА, даже если вы специально после
разрыва связи выполните команды .Close и .Open, все равно ADODB.Connection не установить связь, а лишь
создаст видимость ее установления: флаг Active=true.
Но на деле, при проверке такого фиктивного соединения (например, запрос таблицы), вылетает ошибка об
отсутствии связи. Ошибка эта повторяется довольно просто:
- создайте Delphi-проект (или даже на другом языке) с использованием ADODB.Connection, таблицы и DBGrid, связанных друг с другом. Сделайте property AdoDB.Connection.LoginPrompt = false. И задайте такую строку соединения с БД, чтобы она ссылалась на базу данных по локальной сети.
- добавьте Кнопку1 на форму, и поставьте на ее нажатие код, который будет выполнять методы .Close (в Try..Except..End), затем .Open у ADODB.Connection.
- добавьте Кнопку2 на форму, поставьте на ее нажатие код, который выведет состояние свойства ADODB.Connection.Active.
- запустите программу, нажмите Кнопку1, соединение произойдет. Проверьте это, нажав Кнопка2.
- теперь специально разорвите связь между вашим компьютером, и компьютером с БД. Как умеете: или выдерните прямо сетевой шнур, или отключите соединение..
- проверьте состояние ADODB.Connection, нажав Кнопка2: оно будет все ще думать, что оно подключено к БД.
- если вы затем вновь соедините сеть, то ADODB.Connection даже ничего и не заметит. А при попытке запроса через такое "убитое" соединение будет вылезать ошибка.
Будьте внимательны! Учитывайте данную ошибку. (повторяется на версиях ADO - 2.5, 2.8)
2) Кроме того, у ADODB.Connection существует свойство, которое указывает (в секундах) через какое время, если соединение не используется, оно само разорвет связь.
Чтение записей Отличие от традиционного ADODB.Connection - умеет читать самые разные типы данных. //******************************************* Процедура Сформировать() //Открываем соединение ado.Open("Driver={Microsoft Access Driver (*.mdb)};Dbq="+ф_ИмяMDB+";Uid=Admin;Pwd=;"); таб=СоздатьОбъект("Таблица"); таб.ИсходнаяТаблица("Таблица"); таб.ВывестиСекцию("Шапка"); таб.Опции(0); Запрос="SELECT * FROM ТестоваяТаблица;"; ado.Execute(Запрос); Пока ado.EOF=0 Цикл //Цикл по записям таб.ВывестиСекцию("Строка|Начало"); зн=ado.GetField("id"); таб.ПрисоединитьСекцию("Строка|Данные"); зн=ado.GetField("text1"); таб.ПрисоединитьСекцию("Строка|Данные"); зн=ado.GetField("memo1"); таб.ПрисоединитьСекцию("Строка|Данные"); зн=ado.GetField("Байт1"); таб.ПрисоединитьСекцию("Строка|Данные"); зн=ado.GetField("Целое1"); таб.ПрисоединитьСекцию("Строка|Данные"); зн=ado.GetField("ДлинноеЦелое1"); таб.ПрисоединитьСекцию("Строка|Данные"); зн=ado.GetField("Single1"); таб.ПрисоединитьСекцию("Строка|Данные"); зн=ado.GetField("Double1"); таб.ПрисоединитьСекцию("Строка|Данные"); зн=ado.GetField("КодРепликации1"); таб.ПрисоединитьСекцию("Строка|Данные"); зн=ado.GetField("ДатаВремя1"); таб.ПрисоединитьСекцию("Строка|Данные"); зн=ado.GetFieldAsDateTime("ДатаВремя1"); таб.ПрисоединитьСекцию("Строка|Данные"); зн=ado.GetField("Денежный1"); таб.ПрисоединитьСекцию("Строка|Данные"); зн=ado.GetField("Логический1"); таб.ПрисоединитьСекцию("Строка|Данные"); зн=ado.GetField("Действительное1"); таб.ПрисоединитьСекцию("Строка|Данные"); ado.MoveNext(); //Переходим к след. записи КонецЦикла; ado.Close(); //Закрываем соединение таб.Показать("Запрос"); КонецПроцедуры Добавление записейВ этом примере я использую параметризацию: Prepare и Bind. Это позволяет исключить атаки злоумышленников, или сбои в работе, если я по какой-то причине не проставлю кавычки для экранирования текстовых полей. Полноценная параметризация не реализована.
//____________________________________________________________________________________________________ Процедура ф_Добавить() // //Открываем соединение ado.Open("Driver={Microsoft Access Driver (*.mdb)};Dbq="+ф_ИмяMDB+";Uid=Admin;Pwd=;"); //Подготовка запроса Запрос="INSERT INTO ТестоваяТаблица (text1,memo1,Байт1,Целое1, ДлинноеЦелое1, Single1, Double1,КодРепликации1,ДатаВремя1,Денежный1, Логический1,Действительное1) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)"; ado.PrepareQuery(Запрос); ado.Bind("это text"); ado.Bind("это memo"); ado.Bind(257); ado.Bind(32767); ado.Bind(9999999); ado.Bind(12.34); ado.Bind(56.78); ado.Bind("{AB634001-F13D-11D0-A459-004095E1DAEA}"); ado.Bind('26.01.2007'); ado.Bind(33.33); ado.Bind(1); ado.Bind(111); ado.Execute(); ado.Close(); //Закрываем соединение КонецПроцедуры Обновление записейДанный пример смотрит, есть ли запись с указанным ID. Если ее нет, то добавляет (Insert) ее, затем делает Update.
//____________________________________________________________________________________________________ Процедура ф_Обновить() // //Открываем соединение ado.Open("Driver={Microsoft Access Driver (*.mdb)};Dbq="+ф_ИмяMDB+";Uid=Admin;Pwd=;"); Запрос="SELECT id FROM ТестоваяТаблица WHERE id=?;"; ado.PrepareQuery(Запрос); ado.Bind(1); ado.Execute(); Если ado.EOF=1 Тогда Запрос="INSERT INTO ТестоваяТаблица (id) VALUES (?)"; ado.PrepareQuery(Запрос); ado.Bind(1); ado.Execute(); КонецЕсли; Запрос="UPDATE ТестоваяТаблица SET "+ "text1=?,memo1=?,Байт1=?,Целое1=?,ДлинноеЦелое1=?, Single1=?, Double1=?, КодРепликации1=?,ДатаВремя1=?,Денежный1=?,Логический1=?,Действительное1=?"+ " WHERE id=?"; ado.PrepareQuery(Запрос); ado.Bind("это text"); ado.Bind("это memo"); ado.Bind(257); ado.Bind(32767); ado.Bind(9999999); ado.Bind(12.34); ado.Bind(56.78); ado.Bind("{AB634001-F13D-11D0-A459-004095E1DAEA}"); ado.Bind('26.01.2007'); ado.Bind(33.33); ado.Bind(1); ado.Bind(111); ado.Bind(1); ado.Execute(); ado.Close(); //Закрываем соединение КонецПроцедуры Удобное обновление записей Этот пример делает то же самое, что и предыдущий, но записан в более удобном для восприятия виде.//____________________________________________________________________________________________________ Процедура ф_Обновить1() // //Открываем соединение ado.Open("Driver={Microsoft Access Driver (*.mdb)};Dbq="+ф_ИмяMDB+";Uid=Admin;Pwd=;"); ado.OpenRec("ТестоваяТаблица"); ado.KeyField("id", 1); //Ключевое поле ado.DataField("text1", "это текст"); ado.DataField("memo1", "это memo"); ado.DataField("Байт1", 255); ado.DataField("Целое1", 32767); ado.DataField("ДлинноеЦелое1", 88889999); ado.DataField("Single1", 12.34); ado.DataField("Double1", 56.78); ado.DataField("КодРепликации1", "{AB634001-F13D-11D0-A459-004095E1DAEA}"); ado.DataField("ДатаВремя1", '26.01.1976'); ado.DataField("Денежный1", 100.55); ado.DataField("Логический1", 1); ado.DataField("Действительное1", 1234); ado.SaveRec(); ado.Close(); //Закрываем соединение КонецПроцедуры Работа со ссылочными типами Приведенный ниже пример обновляет таблицу, которая содержит код, наименование и ссылку на элемент товаров. Метод GetFieldAsObject("Товар") извлекает товар из таблицы как ссылку на объект 1С:Предприятие! //____________________________________________________________________________________________________ Процедура ф_Реквизиты() //Открываем соединение ado.Open("Driver={Microsoft Access Driver (*.mdb)};Dbq="+ф_ИмяMDB+";Uid=Admin;Pwd=;"); спр=СоздатьОбъект("Справочник.Товары"); спр.ВыбратьЭлементы(); Пока спр.ПолучитьЭлемент() = 1 Цикл Запрос="SELECT Код FROM Товары WHERE Код=?;"; ado.PrepareQuery(Запрос); ado.Bind(0+спр.Код); ado.Execute(); Если ado.EOF=1 Тогда Запрос="INSERT INTO Товары (Код) VALUES (?)"; ado.PrepareQuery(Запрос); ado.Bind(0+спр.Код); ado.Execute(); КонецЕсли; Запрос="UPDATE Товары SET "+ "Товар=?,Наименование=?"+ " WHERE Код=?"; ado.PrepareQuery(Запрос); ado.Bind(спр.ТекущийЭлемент()); ado.Bind(спр.Наименование); ado.Bind(0+спр.Код); ado.Execute(); КонецЦикла; //Читаем элементы Запрос="SELECT * FROM Товары"; ado.Execute(Запрос); Пока ado.EOF=0 Цикл //Цикл по записям зн=ado.GetField("Код"); Сообщить("Код="+зн+" "); зн=ado.GetField("Наименование"); Сообщить("Наименование="+зн+" "); зн=ado.GetFieldAsObject("Товар"); Сообщить("Товар="+зн+" "); ado.MoveNext(); //Переходим к след. записи КонецЦикла; ado.Close(); //Закрываем соединение КонецПроцедуры То же самое, с использованием OpenRec-SaveRec. //____________________________________________________________________________________________________ Процедура ф_Реквизиты1() //Открываем соединение ado.Open("Driver={Microsoft Access Driver (*.mdb)};Dbq="+ф_ИмяMDB+";Uid=Admin;Pwd=;"); //Пишем товары в таблицу спр=СоздатьОбъект("Справочник.Товары"); спр.ВыбратьЭлементы(); Пока спр.ПолучитьЭлемент() = 1 Цикл ado.OpenRec("Товары"); ado.KeyField("Код", 0+спр.Код); //Ключевое поле ado.DataField("Наименование", спр.Наименование); ado.DataField("Товар", спр.ТекущийЭлемент()); ado.SaveRec(); КонецЦикла; //Читаем элементы Запрос="SELECT * FROM Товары"; ado.Execute(Запрос); Пока ado.EOF=0 Цикл //Цикл по записям зн=ado.GetField("Код"); Сообщить("Код="+зн+" "); зн=ado.GetField("Наименование"); Сообщить("Наименование="+зн+" "); зн=ado.GetFieldAsObject("Товар"); Сообщить("Товар="+зн+" "); ado.MoveNext(); //Переходим к след. записи КонецЦикла; ado.Close(); //Закрываем соединение КонецПроцедурыПолучение имен полей по их номеру (13.02.2007) Запрос="SELECT * FROM ТестоваяТаблица;"; ado.Execute(Запрос); Для й= 0 По ado.КоличествоПолей-1 Цикл Сообщить("Имя поля: "+ado.ИмяПоля(й)); КонецЦикла;