Ini и Database

© 2003 Vladimir Khonin

Удобство работы в среде разработки очень часто требует наличия открытого коннекта и запросов, когда как эксплуатация приложения зачастую требует определение пути к базе данных на момент запуска приложения. Один из вариантов решения этого противоречия предлагаю на ваш суд.

Кратко суть метода это использование директивы DEFINE и ini файла.

Почему ini, а не реестра? Потому, что использование первого дает такие преимущества как Linux-совместимость и, главное, возможность использовать одновременно несколько копий приложения с различными настройками на одном компьютере.

Теперь как использовать DEFINE и обойти возникающие проблемы.

Для начала заводим дополнительный дата модуль, копируем (почему копируем далее) туда объекты типа TpFIBDatabase, TpFIBTransaction из старого дата модуля. Получаем что то вроде этого:

object DB: TDB
  OldCreateOrder = False
  Left = 192
  Top = 107
  Height = 150
  Width = 112
  object db: TpFIBDatabase
    Connected = True
    DBName = '127.0.0.1:c:\prg\MyProject.gdb'
    DBParams.Strings = (
      'lc_ctype=WIN1251'
      'password=masterkey'
      'user_name=SYSDBA')
    DefaultTransaction = tr
    SQLDialect = 3
    Timeout = 0
    Left = 9
    Top = 6
  end
  object tr: TpFIBTransaction
    Active = True
    DefaultDatabase = db
    TimeoutAction = TARollback
    Left = 9
    Top = 57
  end
end
unit U_DB;

interface

uses
  Classes, FIBDatabase, pFIBDatabase;

type
  TDB = class(TDataModule)
    db: TpFIBDatabase;
    tr: TpFIBTransaction;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  DB: TDB;

implementation

{$R *.dfm}

end.

В старом дата модуле добавляем ссылку на новый дата модуль:

Uses …u_db,…

Далее необходимо поменять привязки к перемещаемым объектам. Проще всего это сделать не в IDE Delphi, а в блокноте. Сохраните DFM как текстовый файл. Закройте старый модуль в IDE Delphi и откройте его DFM в чем-нибудь вроде блокнота. Пройдитесь заменой по ссылкам и удалите описание ранее скопированных объектов. Удалите описание скопированных объектов в PAS файле. Если все сделали правильно, то теперь модуль должен спокойно открыться в IDE Delphi и ни у одного объекта свойство active не сбросится в false.

Теперь проверьте файл проекта. Создание нового модуля данных должно идти до создания старого, в противном случае работать ничего не будет.

Обратите внимание, разделение модулей может вызвать проблемы при открытии проекта в IDE Delphi. Для того чтоб избежать проблем следует перед редактированием форм открыть новый модуль, потом старый, а потом только нужную форму.

А теперь то, ради чего все эти мучения:

Сохраняем новый модуль в отдельный каталог, например DesignTime. Копируем этот каталог (DesignTime) со всем содержимым в каталог RunTime.

Правим файл проекта. Вместо строки:

U_DB in 'RunTime\U_DB.pas' {DB: TDataModule},
Вставляем следующую конструкцию:
{$IFDEF AllCompil}
U_DB in 'RunTime\U_DB.pas' {DB_RT: TdataModule},
{$ELSE}
U_DB in 'DesignTime\U_DB.pas' {DB_DT: TdataModule},
{$ENDIF}

То есть даем директивы компилятору, какой модуль брать, а также инструкции IDE Delphi отображать в списке модулей один Db модуль как DB_RT, а другой DB_DT.

Что это нам дает: если строчки {$DEFINE AllCompil} выше нет (а ее пока нет – мы ж не писали Нам смешно), то берется 'DesignTime\U_DB.pas' иначе 'RunTime\U_DB.pas'.

Кроме того, инструкцию {$DEFINE AllCompil} можно не вставлять в файл, а передавать как параметр компилятору. Исходя из этого факта, для компиляции проекта пишем следующий бат файл:

C:\
cd c:\prg\myProject
DCC32.EXE -b -h -w -eC:\Prg\myProject\exe –DallCompil myProject.dpr >C:\Prg\myProject\myProject.log

Первые две строчки – переходим в каталог проекта (их можно не писать).
Далее инструкции компилятору:
BBuild all units
HOutput hint messages
WOutput warning messages
EpathExecutable output directory
DdefinesDefine conditional symbol
>C:\Prg\myProject\myProject.log – выводим всю информацию в файл, переписывая старый. (Если нужно дописывать удвойте скобку (>>))

Еще такая тонкость – в каталоге $Delphi$\bin есть файл DCC32.CFG в нем нужно указать пути к используемым библиотекам иначе вряд ли что то скомпилируется.

Запуская этот командный файл, мы получаем исполняемый файл использующий 'RunTime\U_DB.pas'.

Помимо прочего в этот командный файл можно заложить другие команды – компиляцию ресурсов, сохранение версии проекта и тому подобное.

Теперь разберемся с процедурой инициализации базы данных в 'RunTime\U_DB.pas'. Вставьте в модуль проекта {$DEFINE AllCompil} где-нибудь выше uses, чтоб отладить модуль 'RunTime\U_DB.pas' и начнем его редактировать, ведь пока он не отличим от 'DesignTime\U_DB.pas'. В списке модулей проекта видны оба модуля - DB_DT и DB_RT. Выберите DB_RT.

Укажите Connected = False и займемся процедурой запуска.

Вставим в секцию interface функцию, открывающую нашу базу:

procedure openDB_GetIni(s:string):string;
В секцию implementation добавьте:
uses sysutils, IniFiles;

И саму процедуру коннекта:
procedure openDB_GetIni; Const iniName = 'MyProject.ini'; var r:TIniFile; s:string; begin s:= ExtractFilePath(Paramstr(0))+ iniName; {Ищем ini файл в каталоге программы, если находим, то открываем его, если нет, то отдаем его поиски и создание стандартному поведению TiniFile.} if FileExists(s) then r := TiniFile.create(s) else r := TiniFile.create(iniName); try {Считываем из ini файла путь к базе или берем параметр по умолчанию} db.db.DBName:= r.ReadString('Path', 'Base', db.db.DBName); {Открываем базу и вперед…} db.db.Open; db.tr.StartTransaction; finally r.free; end; end;
Добавьте в файл проекта вызов этой процедуры между Application.CreateForm(TDB, DB) и Application.CreateForm(TDM, DM).
{$IFDEF AllCompil} openDB_GetIni; {$ENDIF}

И опля! Можно тестировать, убирать {$DEFINE AllCompil} из файла проекта и работать!

PS: Все это написано на примере FIBPlus, но с тем же успехом применимо практически к любым другим компонентам доступа к БД.

Copyright© 2003 Vladimir Khonin  Специально для Delphi Plus

2011123456789101112
2010123456789101112
2009123456789101112
2008123456789101112
2007123456789101112
2006123456789101112
2005123456789101112
2004123456789101112
2003123456789101112
2002123456789101112
2001123456789101112
2000123456789101112
1999123456789101112

Последние статьи
Литература