Delphi, С++Builder и базы данных: вопросы и
ответы
Наталия Елманова
После публикации в 1997-98 гг. цикла статей,
посвященных C++Builder, в адрес редакции поступило
много вопросов, связанных с проблемами
использования баз данных в приложениях Delphi и
C++Builder. Данная статья посвящена ответам на
некоторые наиболее часто встречающиеся из них.
В статье "Создание серверов приложений с
помощью Delphi 3" вы написали, что подключались к
Personal Oracle с помощью BDE. Я очень прошу вас
рассказать, как вы это сделали. Для меня пока это
остается загадкой.
Доступ к Personаl Oracle (как и к любой другой версии
СУБД Oracle) осуществляется следующим образом.
Сначала нужно запустить сервер (в случае Personal Oracle
для Windows 95 это отдельное приложение, в случае Oracle
для Windows NT - набор сервисов, обслуживающих
конкретную базу данных) и настроить клиентскую
часть Oracle. Для этого следует запустить утилиту
SQLNet Easy Configuration (в случае Oracle 8 - Oracle Net8 Easy Config) и с ее
помощью создать описание псевдонима базы данных
Oracle (для него, как и в BDE, используется термин alias,
но это не то же самое, что псевдоним BDE). При
создании этого описания важны три параметра.
Первый из них - сетевой протокол, с помощью
которого осуществляется доступ к серверу Oracle
(IPX/SPX, TCP/IP и др.). Второй параметр - местоположение
сервера в сети. В случае Personal Oracle это обычно
компьютер с IP-адресом 127.0.0.1 (это специальный
адрес для доступа к локальному компьютеру, так
называемый TCP Loopback Address, который обычно имеет URL
http://localhost/). Третий параметр - имя базы данных. По
умолчанию в случае Personal Oracle она называется ORCL. В
общем случае имя может быть любым, но это должно
быть имя уже существующей базы данных, с которой
вы собираетесь работать.
В принципе все описания псевдонимов Oracle
хранятся в текстовом файле TNSNAMES.ORA, который можно
редактировать вручную.
Далее следует запустить утилиту SQL Plus и
проверить соединение клиента с сервером. Обычно
в качестве имени пользователя используется имя
SYSTEM и пароль MANAGER (если вы сами администрируете
сервер). Если же сервер был установлен раньше,
узнайте у администратора базы данных, каким
именем и паролем следует воспользоваться. Помимо
имени пользователя и пароля, SQL Plus запросит так
называемую строку связи, в которой
должно содержаться имя сервиса, который был
создан вами перед этим. При удачном соединении в
SQL Plus появится соответствующее сообщение.
Отметим, что утилита Oracle Net8 Easy Config позволяет
протестировать соединение непосредственно в
процессе создания описания сервиса.
Если соединение с сервером было неудачным,
стоит проверить, поддерживается ли указанный
сетевой протокол, виден ли в сети компьютер, на
котором установлен сервер, и, если нужно, внести
изменения в описание сервиса.
Теперь можно, наконец, заняться настройкой BDE. В
качестве Server Name следует указать имя псевдонима
Oracle (его можно просто выбрать из выпадающего
списка, так как BDE Administrator также обращается к
файлу TNSNAMES.ORA). После этого нужно проверить
соединение с сервером через BDE с помощью BDE
Administrator или SQL Explorer.
Если соединение не устанавливается и
появляется сообщение "Vendor initialization
failed", стоит убедиться, что динамическая
загружаемая библиотека, указанная в параметре
Vendor Init драйвера Oracle, действительно присутствует
на данном компьютере. На всякий случай стоит
скопировать ее в папку Windows\System, так
как некоторые ранние версии BDE в Windows 95 не находят
эту библиотеку в подкаталоге Bin
каталога, в котором установлен клиент Oracle, в силу
ограничений, налагаемых этой операционной
системой на длину переменной окружения PATH.
Отметим также, что при использовании Oracle 8 нужно
использовать версию не ниже 8.0.4; в случае
использования более ранней версии следует
обновить ее до 8.0.4.
Недавно я перешел на использование Oracle, но
все мои попытки использовать компонент TStoredProc
оказываются неудачными. Почему?
Причины неработоспособности компонента TStoredProc
могут быть следующими.
Во-первых, при использовании ODBC-доступа может
оказаться, что применяемый вами ODBC-драйвер не
поддерживает хранимые процедуры (как известно,
не все ODBC-драйверы их поддерживают).
Во-вторых, имеется известная проблема, описание
которой содержится в разделе Developers Support
корпоративного сайта Inprise (http://www.inprise.com). Дело в том, что число
параметров хранимой процедуры, с которой
взаимодействует компонент TStoredProc,
не должно превышать 10. В случае, если реальное
число параметров превышает 10, многие
разработчики переписывают хранимые процедуры
так, чтобы они использовали строковые параметры,
содержащие по несколько реальных параметров.
Дает ли Delphi возможность корректно прервать
выполнение SQL-запроса к серверу Oracle с помощью BDE?
Например, чтобы при использовании с SQL Plus после
отправки SQL-запроса на выполнение на экране
появлялось окно с кнопкой Cancel, которое давало бы
возможность в любой момент прервать выполнение
этого запроса?
Насколько мне известно, для этой цели лучше
всего использовать функции Oracle Call Interface
(низкоуровневый API Oracle). В комплекте поставки Oracle
есть соответствующие примеры для C, и переписать
их на Pascal несложно.
Некоторые драйверы SQL Link позволяют прекратить
выполнение запроса, если время его выполнения
превышает заранее заданное значение (параметр MAX
QUERY TIME соответствующего драйвера). Однако драйвер
ORACLE, к сожалению, в их число не входит.
Что необходимо предпринять, чтобы
сгенерировать из ERwin таблицы для локальной базы
данных Paradox 5.0? На компьютере установлены Delphi 4.0 и
MetaBase.
Для этого требуется установить ODBC-драйвер для
этой версии Paradox той же разрядности, что и ERwin.
Затем нужно описать соответствующий ODBC-источник,
и он будет доступен в ERwin.
Не могли бы вы подсказать, как заблокировать
функцию вставки записи непосредственно в
компоненте TDBGrid с сохранением всех
остальных возможностей редактирования таблицы.
Наиболее разумным представляется создать
обработчик события OnBeforeInsert
компонента TTable, TQuery
или TClientDataSet, данные из которых
отображаются в TDBGrid. Сам компонент TDBGrid
не имеет подходящего события для обработки, так
как это компонент, предназначенный только для
создания пользовательского интерфейса, а в
данном случае следует, по существу, запретить
добавление записей в таблицу.
В мой комплект Borland C++ Builder не входит Visual Query
Builder. Могу ли я связать две таблицы без него?
Безусловно, две таблицы можно связать и без VQB.
Самый простой способ - запустить Database Form
Wizard и связать две таблицы, используя TQuery.
Те два запроса, которые при этом получатся (один
из них - параметризованный), можно использовать
как образец.
Кроме того, можно просто написать вручную
необходимый запрос к любому числу таблиц и
поместить его в свойство SQL
компонента TQuery. Все инструменты
для генерации запросов (Visual Query Builder,
SQL Builder и др.) просто предоставляют
для этого визуальные средства, а результатом их
работы является именно текст запроса, помещаемый
в это свойство.
Я установил Borland C++ Builder 3.0 Client/Server Suite и InterBase
Server 5.1.1. (автоматически с ним установился InterBase 5.x
Driver by Visigenic). Но у меня не работают хранимые
процедуры. Например: процедура правильно
откомпилирована, и вызов ее из C++ Builder
осуществляется с помощью выполнения оператора
StoredProc1->ExecProc();
При этом возникает следующая ошибка :
"Capability not supported. General SQL error. [Visigenic][ODBC
InterBase 4.x Driver] Driver not capable".
ODBC-драйвер может не поддерживать хранимые
процедуры. В этом случае стоит попытаться
использовать драйвер SQL Link (он
должен быть в C++ Builder 3.0 Client/Server Suite). Для этого
нужно создать для вашей базы данных псевдоним
типа INTRBASE. В этом случае хранимые процедуры
должны работать.
Если хранимые процедуры, тем не менее, остаются
недоступными, стоит проверить, что и в какой
последовательности было установлено на ваш
компьютер. Такие неприятности могут возникать,
если, например, вы установили какой-либо продукт,
написанный на Delphi 2, после C++Builder 3. В этом случае
можно переустановить BDE, взяв его последнюю
версию на сайте Inprise (http://www.inprise.com
— все зарегистрированные пользователи C++ Builder 3.0
Client/Server Suite имеют право это сделать.
При удалении записей из таблицы dBase с помощью
компонента TTable они просто приобретают
признак удаления, и я никак не могу добиться их
физического удаления. Как быть?
Ваша проблема решается просто - для физического
удаления записей нужно использовать функцию DbiPackTable
(ее описание есть в справочном файле BDE).
При добавлении новых записей с помощью
метода TTable.AppendRecord в индексированную
таблицу FoxPro через какое-то время (то есть при
одновременном добавлении большого количества
записей) возникает ошибка:
"Access to table disabled because of previous error. Read failure.
File <имя_файла.cdx>".
Возможно, причина заключается в том, что
операции чтения-записи в файл, содержащий
таблицу FoxPro, особенно при использовании
кэширования, предоставляемого операционной
системой, конфликтуют с содержимым индексного
файла (это часто происходит при
многопользовательской работе). Дело в том, что
ранние версии dBase, FoxPro, Clipper работали с
неподдерживаемыми индексами, то есть индексные
файлы не обновлялись одновременно с таблицей, и
для их синхронизации требовалось выполнять
специальные операции. Но соответствующие
средства разработки, применявшиеся в то время,
обычно не поддерживали никаких аналогов
транзакций - записи чаще всего вставлялись по
одной.
В случае применения старых версий формата FoxPro
следует избегать кэширования при выполнении
дисковых операций с файловым сервером,
содержащим базу данных FoxPro. Кроме того, следует
проверить и, если необходимо, изменить в
настройках BDE параметры MINBUFSIZE, MAXBUFSIZE, LOCAL SHARE -
возможно, проблема заключается в недостаточной
величине буферов BDE для кэширования данных или в
одновременном доступе к данным приложений,
использующих и не использующих BDE.
Еще одним из способов решения этой проблемы (самым
радикальным) является замена FoxPro на какую-нибудь
из серверных СУБД. Например, InterBase неплохо
справляется с одновременным вводом большого
количества записей благодаря некоторым
специфическим особенностям архитектуры этого
сервера.
Позволяет ли QuickReport выгружать данные в
формате Microsoft Excel?
Quick Report не позволяет выгружать данные в формате
Microsoft Excel. Но последние его версии позволяют
сохранять отчеты в формате CSV (Comma Separated Value) и HTML, и
оба эти формата можно прочесть с помощью Excel.
Помимо этого, для генерации отчета можно
использовать автоматизацию Excel (Automation, ранее
назвалось OLE Automation. — Прим. ред.), вообще не
прибегая к использованию QuickReport.
Как можно создать свою форму просмотра
отчетов QuickReport в С++Builder?
Для создания собственных окон просмотра отчета
можно использовать компонент TQRPreview.
Для этой цели следует создать форму (назовем ее PreviewForm),
поместить на нее компонент TQRPreview,
сослаться на нее в форме, содержащей отчет, и в
форме, из которой вызывается просмотр отчета. Код
для показа отчета выгладит примерно так:
Далее создадим обработчик события OnPreview
компонента TQuickRep:
После этого данный отчет будет
появляться не в стандартном окне просмотра, а в
форме PreviewForm.
Возможно ли использование компонентов Decision
Support System при генерации отчетов в QuickReport и,
если да, то каким образом? Если QuickReport не подходит
для этих целей, то какие другие варианты вы
можете посоветовать?
Самый простой способ - использовать компоненты TQRLabel,
текст в которых динамически меняется во время
печати (то есть способ, которым можно напечатать
все, что угодно, написав при этом немного кода). В
принципе можно записать двухмерное сечение куба
во временную таблицу или в компонент TClientDataSet,
написав соответствующий цикл, и сделать отчет на
ее основе.
Использование DecisionQuery в качестве
источника данных для отчета также вполне
возможно.
Другие возможные варианты - это использование
автоматизации Word или Excel либо вычисление сумм
внутри отчета. Можно также использовать другие
генераторы отчетов - например, с помощью Crystal Reports
можно создавать отчеты, содержащие кросс-таблицы.
Как корректно подключить Crystal Reports к Delphi ?
В составе Crystal Reports Professional имеется VCL-компонент
для Delphi, компонент ActiveX, модуль CRPE32.PAS,
в котором объявлены все функции и структуры Print
Engine API, и описание опубликованных методов Crystal
Reports как сервера автоматизации. Соответственно
есть следующие возможности подключения Crystal Reports
к Delphi:
- Использование функций Report Engine API из библиотеки CRPE32
DLL. В этом случае следует добавить в
проект модуль CRPE32.PAS и сослаться на
этот модуль в предложении uses. Ниже приведен
пример соответствующего кода:
Следует помнить, что строковые
параметры, передаваемые в функции Print Engine API,
представляют собой тип данных PChar,
а не стандартные строки, используемые в Pascal,
поэтому для передачи таких параметров, как,
например, имя отчета, следует осуществить
преобразование типов с помощью функции StrPCopy.
Для успешной компиляции подобных приложений
файл CRPE32.PAS должен находиться в том
же каталоге, что и разрабатываемое приложение,
либо в каталоге Delphi\Lib.
- Использование VCL-компонента из комплекта
поставки (для этого следует установить его в
палитру компонентов Delphi). Естественно, этот
компонент инкапсулирует те же самые функции Print
Engine API. Существуют также аналогичные компоненты
третьих фирм (например, компонент от SupraSoft Ltd.,
http://www.suprasoft.com).
- Использование компонента ActiveX фирмы Crystal Reports.
Этот компонент ActiveX может быть установлен в
палитру компонентов Delphi. Он обладает набором
свойств и методов, более или менее сходным с
соответствующим VCL-компонентом из комплекта
поставки Crystal Reports Professional.
- Использование Crystal Reports как сервера
автоматизации. В справочной системе Crystal Reports
имеется подробное описание иерархии вложенных
объектов и их методов (и внушительный набор
примеров для Visual Basic, аналоги которых несложно
создать и на языке Pascal). Ниже приведен пример
соответствующего кода:
- Можно также сделать отчет в виде
исполняемого файла и вызвать его из приложения.
Но в этом случае передать параметры в отчет не
удастся.
|