Delphi, С++Builder и базы данных: вопросы и ответы
Наталия Елманова
Компьютер Пресс - CD, 1999, N 8
Copyright N.Elmanova & ComputerPress Magazine.
После публикации в 1997-98 гг. цикла статей, посвященных C++Builder, в адрес
редакции поступило много вопросов, связанных с проблемами использования баз
данных в приложениях Delphi и C++Builder. Данная статья посвящена ответам на
некоторые наиболее часто встречающиеся из них.
В статье "Создание серверов приложений с помощью Delphi 3" вы написали,
что подключались к Personal Oracle с помощью BDE. Я очень прошу вас рассказать,
как вы это сделали. Для меня пока это остается загадкой.
Доступ к Personаl 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). Третий
параметр - имя базы данных. По умолчанию в случае 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. Дело в том, что число параметров
хранимой процедуры, с которой взаимодействует компонент TStoredProc, не должно
превышать 10. В случае, если реальное число параметров превышает 10, многие
разработчики переписывают хранимые процедуры так, чтобы они использовали строковые
параметры, содержащие по несколько реальных параметров.
Есть ли возможность в Delphi как-то корректно прервать выполнение SQL запроса
к серверу Oracle с помощью BDE? Например, при использованиис SQL Plus после
отправки на выполнение SQL-запроса на экране появляется окно с кнопкой Cancel,
благодаря чему мы имеем возможность в любой момент прервать выполнение этого
запроса. Можно ли что-то подобное сделать в Delphi?
Насколько мне известно, для этой цели лучше всего использовать функции 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 с сохранением всех остальных возможностей
редактирования таблицы.
Наиболее разумным представляется создать обработчик события BeforeInsert компонента
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- все зарегистрированные пользователи 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 на какую-нибудь из серверных СУБД. Например, IB Database неплохо справляется
с одновременным вводом большого количества записей благодаря некоторым специфическим
особенностям архитектуры этого сервера.
Позволяет ли QuickReport выгружать данные в формате Microsoft Excel?
Quick Report не позволяет выгружать данные в формате Microsoft Excel. Но последние
его версии позволяют сохранять отчеты в формате CSV (Comma Separated Value)
и HTML, и оба эти формата можно прочесть с помощью Excel.
Помимо этого, для генерации отчета можно использовать автоматизацию Excel, вообще
не прибегая к использованию QuickReport.
Как можно создать свою форму просмотра отчетов QuickReport в С++Builder?
Для создания собственных окон просмотра отчета можно использовать компонент
TQRPreview. Для этой цели следует создать форму (назовем ее PreviewForm), поместить
на нее компонент TQRPreview, сослаться на нее в форме, содержащей отчет, и в
форме, из которой вызывается просмотр отчета. Код для показа отчета выгладит
примерно так:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
PreviewForm->Show();
QuickReport1->Preview();
}
Далее создадим обработчик события OnPreview компонента TQuickRep:
void __fastcall TQuickReport1::QuickReport1Preview(TObject *Sender)
{
PreviewForm->QRPreview1->QRPrinter = QuickReport1->QRPrinter;
}
После этого данный отчет будет появляться не в стандартном окне просмотра,
а в форме 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:
1. Использование функций Report Engine API из библиотеки CRPE32 DLL. В этом
случае следует добавить в проект модуль CRPE32.PAS и сослаться на этот модуль
в предложении uses. Ниже приведен пример соответствующего кода:
procedure TForm1.Button1Click(Sender: TObject);
VAR RepNam:PChar;
begin
if OpenDialog1.Execute then
begin
If PEOpenEngine then
begin RepNam := StrAlloc(80);
StrPCopy(RepNam, OpenDialog1.Filename);
JN := PEOpenPrintJob(RepNam);
if JN = 0 then
ShowMessage('Ошибка открытия отчета');
StrDispose(RepNam);
end
else
ShowMessage('Ошибка открытия отчета');
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
PEClosePrintJob(JN);
PECloseEngine;
Close;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
PEOutputToWindow(jn,'Пример использования Crystal Reports Print
Engine',30,30,600,400,0,0) ;
if PEStartPrintJob(JN, True) = False then
ShowMessage('Ошибка вывода отчета');
end;
end.
Следует помнить, что строковые параметры, передаваемые в функции Print Engine
API, представляют собой тип данных PChar, а не стандартные строки, используемые
в Pascal, поэтому для передачи таких параметров, как, например, имя отчета,
следует осуществить преобразование типов с помощью функции StrPCopy. Для успешной
компиляции подобных приложений файл CRPE32.PAS должен находиться в том же каталоге,
что и разрабатываемое приложение, либо в каталоге Delphi\Lib.
2. Использование VCL-компонента и комплекта поставки (для этого следует установить
его в палитру компонентов Delphi). Естественно, этот компонент инкапсулирует
те же самые функции Print Engine API. Существуют также аналогичные компоненты
третьих фирм (например, компонент от SupraSoft Ltd., http://www.suprasoft.com).
3. Использование элемента управления Crystal Reports ActiveX. Этот элемент
управления может быть установлен в палитру компонентов Delphi. Он обладает набором
свойств и методов, более или менее сходным с соответствующим VCL-компонентом
из комплекта поставки Crystal Reports Professional.
5. Использование Crystal Reports как сервера автоматизации. В справочной системе
Crystal Reports имеется подробное описание иерархии вложенных объектов и их
методов (и внушительный набор примеров для Visual Basic, аналоги которых несложно
создать и на Pascal). Ниже приведен пример соответствующего кода:
procedure TForm1.Button1Click(Sender: TObject);
var r,rep: Variant;
begin
rep:=CreateOleObject('Crystal.CRPE.Application');
r:=rep.OpenReport('d:\Report2.rpt');
r.RecordSelectionFormula := '{items.ItemNo} = '+Edit1.Text;
r.Preview;
r:=Unassigned;
rep:=Unassigned;
end;
6. Можно также сделать отчет в виде исполняемого файла и вызвать его из приложения.
Но в этом случае в отчет не удастся передать параметры.
|