Создание и модификация таблиц программно

В большинстве случаев, база данных и таблицы в ней проектируются и создаются заранее, например, такими утилитами, как Database Desktop, или СУБД MS Access. Однако иногда приходится создавать таблицы программно, то есть, не во время проектирования приложения, а во время его работы. Предположим, каждый пользователь программы должен иметь свою собственную таблицу в базе данных, или даже свою собственную БД. Сделать это заранее программист не может, ведь неизвестно, сколько пользователей на одном ПК будут работать с программой, и какие у них будут имена.

1. BDE. Простая таблица.

Наиболее простой способ создания таблицы без индексов предлагает механизм доступа к данным BDE. Плюсы данного способа в простоте выполнения, в возможности создания таблиц как текстового типа, так и dBase, Paradox или FoxPro. Суть данного способа заключается в предварительном создании объектов-полей в редакторе полей компонента TTable. Это также означает, что еще на этапе проектирования можно настроить формат объектов-полей по своему усмотрению.

Рассмотрим этот способ на примере.

Создайте новое приложение.

Форму назовите fMain, сохраните модуль под именем Main, а проект в целом назовите как угодно. На форму установите простую панель, очистите ее свойство Caption, а свойству Align присвойте значение alTop.

В левой части панели установите рядом две простые кнопки, а в правой - компонент TDBNavigator с вкладки Data Controls Палитры компонентов.

Ниже панели установите сетку TDBGrid, в ее свойстве Align выберите значение alClient.

У кнопок измените свойство Caption: на первой кнопке напишите "Создать таблицу", на второй - "Открыть таблицу".

Также нам потребуется еще четыре не визуальных компонента. Прямо на сетку, или в любое другое место установите компонент TTable с вкладки BDE, компонент TDataSource с вкладки Data Access, и компоненты TSaveDialog и TOpenDialog с вкладки Dialogs.

Подготовим диалоговые компоненты. Выделите их и присвойте свойству Filter обоих компонентов строку Таблицы dBase|*.dbf

Таким образом, мы указали, что диалоги будут работать только с таблицами типа dBase. Кроме того, у обоих диалогов измените свойство DefaultExt, указав там: dbf

Это свойство указывает расширение файла по умолчаниию, если пользователь не назначит расширения сам.

В свойстве DataSet компонента DataSource1 выберите таблицу Table1.

В свойстве DataSource сетки DBGrid1 и навигатора DBNavigator1 выберите имеющийся DataSource1. Теперь при открытии таблицы она будет отображаться в сетке, а навигатор позволит управлять ей.

Теперь настраиваем компонент Table1. Табличный компонент TTable имеет свойство TableType; компонент TADOTable такого свойства не имеет. Это свойство указывает на тип используемой или создаваемой таблицы. Свойство может иметь следующие значения:

Значения свойства TableType компонента TTable
Значение Описание
ttASCI Таблица содержится в формате обычного текстового файла. Строки и поля разделяются специальными символами - разделителями. Имя файла таблицы имеет расширение *.TXT
ttDBase Таблица содержится в формате dBase, файл по умолчанию имеет расширение *.DBF
ttDefault Компонент определяет тип таблицы по расширению имени файла таблицы. При создании таблицы, если не указано расширение имени файла, принимается тип Paradox.
ttFoxPro Таблица содержится в формате FoxPro, файл по умолчанию также имеет расширение *.DBF
ttParadox Таблица содержится в формате Paradox, файл по умолчанию имеет расширение *.DB

Если выбран тип таблицы (не ttDefault), то будет использован этот тип вне зависимости от расширения указанного имени файла таблицы.

В свойстве TableType компонента Table1 выберите значение ttDBase, то есть, таблица будет работать только с типом dBase. Далее дважды щелкните по компоненту, открыв редактор полей.

Нам нужно будет добавить запланированные ранее поля. Щелкните по редактору правой кнопкой, выберите команду New Field (Новое поле).

В поле Name впишите имя поля, например, FCeloe.

В поле Type выберите тип поля Integer.

В поле Size нужно указывать размер поля, но это справедливо только для текстовых полей и полей типов Memo или BLOB

Убедитесь, что переключатель Field Type установлен на Data, это создаст пустое поле указанного типа. Нажав кнопку "ОК" добавьте объект-поле в редактор полей.

Таким же образом создайте еще несколько разнотипных полей. Каждому полю присвойте уникальное имя. Важно, чтобы вы добавляли только те типы полей, которые поддерживаются выбранным типом таблиц, в нашем случае это dBase. При добавлении типа Memo укажите размер от 1 до 255, например, 50. В этом случае в файле таблицы *.dbf будет сохранен текст поля в 50 символов. Текст, который не уместится в этот размер, будет сохранен в файле Memo с таким же именем, но с расширением *.dbt.

Делать табличный компонент активным на этапе проектирования не нужно. Итак, не имея базы данных, не имея физической таблицы, мы заранее установили тип таблицы и нужные нам поля. Также возможно сразу настроить нужные форматы для каждого поля, изменяя такие его свойства, как DisplayFormat, EditMask, DisplayLabel и др.

Далее осталось непосредственно создать и открыть таблицу. Дважды щелкните по кнопке "Создать таблицу", сгенерировав для нее событие. В процедуру этого события впишите код:

//если пользователь не выбрал таблицу, выходим: if not SaveDialog1.Execute then Exit; //закроем таблицу, если вдруг уже есть открытая: Table1.Close; //вначале устанавливаем адрес базы данных: Table1.DatabaseName:= ExtractFilePath(SaveDialog1.FileName); //теперь устанавливаем имя таблицы: Table1.TableName:= SaveDialog1.FileName; //физически создаем таблицу: Table1.CreateTable; //и открываем ее: Table1.Open; //запишем имя открытой таблицы: fMain.Caption:= 'Таблица - '+ Table1.TableName;

Метод CreateTable() компонента-таблицы создает файл таблицы, и дополнительные файлы (Memo, индексные), если они нужны.

В свойстве DatabaseName табличного компонента вы можете установить любой необходимый вам адрес, мы использовали папку, выбранную диалогом SaveDialog.

Для кнопки "Открыть таблицу" код будет почти таким же:

//если пользователь не выбрал таблицу, выходим: if not OpenDialog1.Execute then Exit; //закроем таблицу, если вдруг уже есть открытая: Table1.Close; //вначале устанавливаем адрес базы данных: Table1.DatabaseName:= ExtractFilePath(OpenDialog1.FileName); //теперь устанавливаем имя таблицы: Table1.TableName:= OpenDialog1.FileName; //открываем таблицу: Table1.Open; //запишем имя открытой таблицы: fMain.Caption:= 'Таблица - '+ Table1.TableName;

BDE. Таблица с ключом и индексами.

В задачу данного раздела входит создание таблицы Paradox с различными типами полей, с первичным ключом и индексами по текстовому полю как в возрастающем, так и в убывающем порядке. Редактор полей компонента TTable при этом вызывать не нужно, добавлять поля мы тоже будем программно. Создайте главную форму такой же, как в предыдущем примере, только кнопка там будет одна. При нажатии на эту кнопку мы должны открыть таблицу, если она существует, или создать и открыть новую таблицу. Располагаться таблица должна в той же папке, откуда запущено приложение. Файл с таблицей Paradox назовем Proba.db, файлы с Memo и индексные файлы сгенерируются автоматически, также с именем Proba, но с разными расширениями.

На форму добавьте компонент TTable с вкладки BDE, свойству Name которого присвойте значение TMy (вместо Table1), а свойству TableType значение ttParadox. Если у вас в приложении есть сетка DBGrid и (или) навигатор DBNavigator, то добавьте также компонент DataSource, который необходимо подключить к таблице TMy, а сетку и навигатор - подключить к DataSource. Здесь следует иметь в виду одну деталь: описание методов создания полей и индексов хранится в модуле DBTables, который подключается к вашей форме сразу, как вы установите компонент TTable. Если же вы используете модуль данных, и устанавливаете табличный компонент там, то и создавать таблицу нужно тоже в этом модуле, а в главной форме лишь вызывать процедуру создания таблицы. Но в нашем простом примере модуля данных нет, модуль DBTables указан в разделе Uses главной формы, и никаких проблем возникнуть не должно.

Код нажатия на кнопку выглядит так:

{Если таблицы нет - создаем и открываем ее, если есть- просто открываем}procedure TfMain.Button1Click(Sender: TObject);begin //если таблица есть - открываем ее и выходим: if FileExists(ExtractFilePath(Application.ExeName) + 'Proba.db') then begin TMy.DatabaseName:= ExtractFilePath(Application.ExeName); TMy.TableName:= 'Proba.db'; TMy.Open; Exit; end; //if {Если дошли до этого кода, значит таблицы еще нет. Указываем данные таблицы:} TMy.DatabaseName:= ExtractFilePath(Application.ExeName); TMy.TableType:= ttParadox; TMy.TableName:= 'Proba'; {Создаем поля:} with TMy.FieldDefs do begin //вначале очистим: Clear; //добавляем поле-счетчик типа автоинкремент: with AddFieldDef do begin Name:= 'Key'; DataType:= ftAutoInc; Required:= True; end; //with //добавляем текстовое поле: with AddFieldDef do begin Name:= 'Name'; DataType:= ftString; Size:= 30; end; //with //добавляем поле дата: with AddFieldDef do begin Name:= 'Date'; DataType:= ftDate; end; //with //добавляем логическое поле: with AddFieldDef do begin Name:= 'MyLog'; DataType:= ftBoolean; end; //with //добавляем целое поле: with AddFieldDef do begin Name:= 'MyInt'; DataType:= ftInteger; end; //with //добавляем вещественное поле: with AddFieldDef do begin Name:= 'MyReal'; DataType:= ftFloat; end; //with //добавляем денежное поле: with AddFieldDef do begin Name:= 'MyCurr'; DataType:= ftCurrency; end; //with //добавляем поле Memo: with AddFieldDef do begin Name:= 'MyMemo'; DataType:= ftMemo; Size:= 20; end; //with end; //with {Создаем ключ и индексы:} with TMy.IndexDefs do begin Clear; //делаем первичный ключ: with AddIndexDef do begin Name:= ''; Fields:= 'Key'; Options:= [ixPrimary]; end; //делаем индекс в возрастающем порядке: with AddIndexDef do begin Name:= 'NameIndxASC'; Fields:= 'Name'; Options:= [ixCaseInsensitive]; end; //делаем индекс в убывающем порядке: with AddIndexDef do begin Name:= 'NameIndxDESC'; Fields:= 'Name'; Options:= [ixCaseInsensitive, ixDescending]; end; end; //with //создаем таблицу: TMy.CreateTable; //и открываем ее: TMy.Open;end;

Разберем приведенный код. Первый блок выполняет проверку на наличие таблицы. Таблица ищется в папке, откуда была запущена программа. Если таблица найдена, то компоненту TMy присваиваются свойства DatabaseName (папка, где располагается таблица) и TableName (имя таблицы). В нашем случае таблица называется Proba.db, но вы можете усложнить программу, используя диалог OpenDialog, как в прошлом примере. В этом случае пользователь сможет выбрать не только имя таблицы, но и ее расположение. Далее таблица открывается, а оператор Exit досрочно завершает выполнение процедуры.

Если выполнение процедуры продолжается, значит, таблица не была найдена. В этом случае мы заполняем свойства компонента-таблицы DatabaseName, TableType и TableName необходимыми значениями.

Далее начинаем добавлять поля. Чтобы уменьшить код, мы используем оператор with. Напомню, что этот оператор создает блок кода, который относится к указанному в with объекту. Так, вместо

with TMy.FieldDefs do begin Clear;

можно было бы написать

TMy.FieldDefs.Clear;

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

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

В простейшем случае в блоке добавления нового поля требуется указать только два свойства объекта-поля: Name (имя поля) и DataType (тип поля). С именем все понятно, а что касается типа поля, то он определяется свойством DataType класса TField. Чтобы получить подробную справку по возможным типам полей, установите курсор в редакторе кода на слове DataType и нажмите <Ctrl+F1>, чтобы вызвать контекстную справку. В списке тем выберите ту тему, которая относится к классу TField, а в открывшейся справке щелкните по ссылке TFieldType (относится к Delphi 7, хотя возможно, имеется и в предыдущих версиях). Откроется страница с подробным описанием типов полей. При использовании этого метода следует сверяться, имеется ли выбранный тип поля в таблицах используемого формата.

Помимо этих двух свойств, при необходимости могут использоваться и другие:

Required - Логическое свойство. Если равно True, то значения поля должны быть уникальными (не могут повторяться). В нашем примере такое свойство имеется у поля, которое мы будем использовать как первичный ключ.

Size - Указывает размер поля. Используется в основном, со строковыми и Memo - полями.

После того, как в список полей были добавлены все необходимые поля, начинаем создание первичного ключа и индексов. Если за список полей отвечает свойство FieldDefs таблицы, то за список индексов отвечает свойство IndexDefs, а за добавление нового индекса - метод AddIndexDef. По аналогии с полями, используем оператор with для уменьшения кода. Для каждого индекса требуется указать по три свойства: Name (имя индекса), Fields (имя поля, по которому строится индекс) и Options (параметры индекса). Параметры индекса указаны в таблице:

Параметры типов индекса
Тип Описание
ixPrimary Первичный индекс (ключ). Не применяется с таблицами типа dBase.
ixUnique Уникальный индекс. Значения этого поля не могут повторяться.
ixDescending Индекс в убывающем (обратном) порядке.
ixExpression Ключевой индекс для таблиц dBase.
ixCaseInsensitive Индекс, нечувствительный к регистру букв.
ixNonMaintained Этот тип используется редко. Он подразумевает, что при редактировании пользователем значения индексируемого поля, индексный файл автоматически не обновляется.

Как видно из примера, свойству Options можно присвоить не один параметр, а список параметров:

Options:= [ixCaseInsensitive, ixDescending];

Далее все просто: указав необходимые поля и индексы, методом CreateTable формируются физические файлы таблицы. Сама таблица имеет расширение *.db, файл с полем Memo - *.mb, остальные файлы содержат созданные индексы.

Для сортировки данных используем индексы. У нас их два -' NameIndxASC ' (в возрастающем порядке) и ' NameIndxDESC ' (в убывающем порядке). Чтобы сортировать данные, например, в убывающем порядке, нужно указать имя соответствующего индекса в свойстве IndexName компонента-таблицы:

TMy.IndexName:= 'NameIndxDESC';

Если же мы хотим снять сортировку, то достаточно просто присвоить этому свойству пустую строку: TMy.IndexName:= '';


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: