Russian Belarusian English German Japanese Ukrainian

Особенности набора данных Table

CuBook3.335

Компонент Table типа TTable представляет собой набор данных, который в текущий момент времени может быть связан только с одной таблицей БД. Этот набор данных формируется на базе навигационного способа доступа к данным, поэтому компонент Table рекомендуется использовать для локальных БД, таких как dBase или Paradox. При работе с удаленными БД следует использовать компонент Query.
 
Связь между таблицей и компонентом Table устанавливается через его свойство TableName типа AnsiString, которое задает имя той таблицы базы данных, которую этот компонент инкапсулирует (и имя файла с данными таблицы). При задании свойства TableName указываются имя файла и расширение имени файла.
 
На этапе разработки приложения имена всех таблиц доступны в раскрывающемся списке Инспектора объектов. В этот список попадают таблицы, файлы которых расположены в каталоге, указанном свойством DatabaseName.
При смене имени таблицы на этапе проектирования приложения свойству Active набора данных автоматически устанавливается значение false. При задании имени таблицы программным способом набор данных предварительно необходимо закрыть, установив его свойству Active значение false. В противном случае генерируется исключение.
Приведем пример, иллюстрирующий, как задается имя таблицы БД:
void __fastcall TForm1::Button1Click(TObject *Sender)
Table1->Close();
if (OpenDialog1->Execute())
Table1->TableName=OpenDialog1->FileName;
Table1->Open();
Здесь нажатие кнопки Button1 приводит к появлению диалогового окна выбора имени файла. При выборе файла таблицы его имя устанавливается в качестве значения свойства TableName. Набор данных Table1 предварительно закрывается и снова открывается уже после смены таблицы. Тип таблицы определяется автоматически по расширению имени файла. При наличии ошибок, например, связанных с нарушением структуры таблицы, выдается соответствующее сообщение, а набор данных остается закрытым.
 
Свойство TableType типа TTableType определяет тип таблицы. Для локальных таблиц это свойство может принимать следующие значения:
  • ttDefault - тип таблицы определяется автоматически по расширению файла;
  • ttParadox - таблица Paradox;
  • ttdBase - таблица dBase;
  • ttFoxPro - таблица FoxPro;
  • TTASCII - текстовый файл, содержащий данные в табличном виде (таблица ASCII).
Если свойство TableType имеет значение ttDefauit (по умолчанию), то тип таблицы определяется по расширению файла:
  • db или отсутствует - таблица Paradox;
  • dbf - таблица dBase;
  • txt - текстовый файл (таблица ASCII).
По умолчанию в состав набора данных Table попадают все записи связанной с ним таблицы. Для отбора записей, удовлетворяющих определенным условиям, используются фильтры.
 
С++ Builder через BDE автоматически поддерживает многопользовательский доступ к локальным таблицам. При этом по умолчанию все пользовательские приложения имеют равные права и могут редактировать содержащиеся в таблицах данные. Чтобы запретить пользователям изменять содержание записей, можно использовать свойство Readonly типа bool. По умолчанию оно имеет значение false, что предоставляет пользователю право изменения записей.
 
Если приложению требуется получить к таблице монопольный доступ, то это можно осуществить через свойство Exclusive типа bool. По умолчанию свойство имеет значение false, и для таблицы, с которой связан набор данных, действует многопользовательский режим доступа. Если установить свойству Exclusive значение true, то приложение получает монопольный доступ к соответствующей таблице, при этом другим приложениям доступ к таблице запрещается. Перед заданием значения свойству Exclusive набор данных должен быть закрыт, т.е. разорвана его связь с таблицей. Если какое-либо приложение или набор данных этого же приложения уже взаимодействует с таблицей, то попытка установить режим монопольного доступа к ней вызовет исключение.
Монопольный режим доступа необходим при выполнении таких операций, как добавление или удаление индекса методами AddIndex и DeleteIndex или очистка таблицы методом EmptyTable.
Такие приложения, как С++ Builder и Database Desktop, также могут осуществлять доступ к таблицам. Поэтому перед отладкой приложения, которое устанавливает монопольный доступ к таблице, необходимо проверить, не работают ли с этой таблицей С++ Builder и/или Database Desktop. В приложении Database Desktop таблицу нужно закрыть, а в среде С++ Builder достаточно через Инспектор объектов установить значение false свойству Active набора данных, связанного с таблицей.
В наборе данных Table можно указать текущий индекс для сортировки, поиска записей и установления связей между таблицами.
 
Текущий индекс устанавливается с помощью свойства IndexName или IndexFieldNames типа AnsiString. На этапе разработки приложения текущий индекс выбирается в списке индексов, заданных при создании таблицы. Все возможные значения свойств IndexName и IndexFieldNames содержатся в раскрывающихся списках, доступных через Инспектор объектов. Оба свойства во многом схожими их использование практически одинаково. Значением свойства IndexName является имя индекса, заданное при создании таблицы, а значением свойства IndexFieldNames является имя поля, для которого был создан индекс. Если индекс состоит из нескольких полей, то для свойства IndexName по-прежнему задается имя этого индекса, а для свойства IndexFiеldNames через точку с запятой перечисляются имена полей, входящие в этот индекс.
 
Вот как текущий индекс задается в программе:
Table1->IndexName = "indName";
Table2->IndexFieldNames = "Name";
Здесь компоненты Table1 и Table2 связаны с одной таблицей, для поля Name которой определен индекс indName. Этот индекс устанавливается в качестве текущего для обоих наборов данных.
 
Для таблиц Paradox сделать текущим индексом ключ (главный индекс) можно только с помощью свойства indexFieldNames, перечислив ключевые поля таблицы, т.к. ключ не имеет имени и поэтому недоступен через свойство IndexName.
 
Задать ключ в качестве текущего индекса можно так:
Table1->IndexFieldNames = "Name;Size";
Здесь для таблицы Paradox, с которой связан компонент Table1, определен ключ, в который входят поля Name и Size. Этот ключ устанавливается в качестве текущего индекса таблицы.
Свойства IndexName и IndexFieldNames взаимозависимы. При установке значения одного из них другое автоматически очищается.
Индекс, устанавливаемый текущим, должен существовать. Если индекс, задаваемый как значение свойства IndexName или IndexFieldNames, для таблицы не существует, то возникает исключение.
 
При смене таблицы, с которой ассоциирован компонент Table, значения свойств IndexName и IndexFieldNames не изменяются автоматически, поэтому программист должен установить нужные значения самостоятельно.
Получить доступ к полям в составе текущего индекса можно с помощью свойств IndexFieldCount и IndexFields.
 
Свойство IndexFieldCount типа int содержит число полей в текущем индексе и доступно для чтения при выполнении приложения.
 
Свойство Db::TField* IndexFields [int index] позволяет обращаться к полям текущего индекса, при этом переменная index задает номер индекса в массиве полей этого индекса (отсчет начинается с нуля). Класс TField представляет собой поле набора данных и имеет большое число свойств и методов.
 
Чаще всего индексы определяются при создании таблицы и в дальнейшем при работе с таблицей не изменяются. Программист может изменять определенные для таблицы индексы динамически, т.е. в процессе выполнения приложения, с помощью методов AddIndex и DeleteIndex.
С помощью методов Addlndex и Deletelndex допускается изменять индексы для таблицы, открытой в режиме монопольного доступа, когда свойство Exclusive имеет значение true.
Метод void __fastcall Addlndex(const AnsiString Name, const AnsiString Fields, Db::TIndexOptions Options, const AnsiString DescFields = ""); добавляет к имеющейся таблице индекс, имя которого задано параметром Name. Входящие в состав индекса поля указываются в параметре Fields; если индекс состоит из нескольких полей, то они разделяются точкой с запятой. Указывать можно только поля, которые входят в структуру таблицы, в противном случае генерируется исключение, а индекс не создается.
 
Параметр Options содержит атрибуты индекса. Он имеет множественный тип и может принимать комбинации следующих значений:
  • ixPrimary (первичный индекс);
  • ixunique (уникальный индекс) - для этого индекса не допускается повторение значений полей в его составе;
  • ixDes с ending (сортировка в порядке убывания значений) - по умолчанию строится индекс, определяющий сортировку по возрастанию;
  • ixExpression (индекс создается на основе выражения) - только для таблиц dBase;
  • ixcaseinsensitive (сортировка не зависит от регистра букв);
  • ixNonMaintained (индекс автоматически не изменяется, если таблица открыта).
Параметр DescFields представляет собой строку, содержащую список имен полей, разделенных точкой с запятой. Поля, определенные в DescFields, представляют собой поля в новом индексе, для которых упорядочение будет установлено в порядке убывания. Поля в определении индекса, но не в списке параметра DescFields, по умолчанию следуют в порядке возрастания. Таким образом, для одного индекса возможно совместное задание порядка возрастания и убывания полей.
 
Приведем пример добавления индекса к таблице:
void __fastcall TForm1::Button1Click(TObjееt *Sender)
{
// Перевод таблицы в режим монопольного доступа
Table1->Close();
Table1->Exclusive = true;
Table1->Open(); // Добавление индекса
Table1->AddIndex("IndNC", "Name;Capital", TIndexOptions() << ixCaselnsensitive); // Закрытие режима монопольного доступа к таблице
Table1->Close();
Table1->Exclusive = false;
Table1->Open{);
}
Здесь к таблице, с которой связан набор данных Table1, добавляется индекс indNC, построенный по полям Name и Capital. Для нового индекса определяется порядок сортировки по возрастанию значений (по умолчанию), не зависящий от регистра букв.
 
Процедура Deletelndex (const Name: String) удаляет из таблицы индекс, имя которого задано параметром Name. При попытке удаления несуществующего индекса генерируется исключение.
 
В программе удаление индекса из таблицы можно реализовать так:
Table1->DeleteIndex("IndNC");
Перед удалением индекса таблица должна быть переведена в режим монопольного доступа аналогично тому, как это происходило при добавлении индекса.
 
Для доступа к информации обо всех индексах, определенных для таблицы и, соответственно, для связанного с ней набора данных, можно использовать свойство IndexDefs типа TIndexDefs. Это свойство доступно на этапах разработки и выполнения приложения. Класс TIndexDefs также имеет полезные свойства и методы.
 
Перед работой с индексами всегда рекомендуется вызывать метод UpDate, который производит обновление информации об индексах так, чтобы значение свойства IndexDefs отражало реальное состояние с учетом сделанных изменений. Свойство count типа int содержит количество индексов и доступно для чтения. Управление количеством индексов осуществляется косвенно, т.е. через другие свойства и методы. Свойство Items [int Index] типа TIndexDef Представляет собой список, содержащий информацию обо всех индексах таблицы. Переменная index Указывает номер индекса в списке, отсчет начинается с нуля. Тип TIndexDef (не путать с классом TIndexDefs) является классом и, в свою очередь, также имеет свойства, главные из которых — Name, Fields и Options.
 
Например, чтобы считать в редактор Edit1 список полей, составляющих второй индекс (первый вторичный индекс), можно использовать следующий код:
Edit1->Text = Table1->IndexDefs->Iterns[1]->Fields;
Свойство Name типа AnsiString содержит имя индекса. Для индексов, построенных на основе выражений (таблицы dBase), и для главного индекса таблиц Paradox вместо имени возвращается пустая строка.
 
Свойство Fields типа AnsiString содержит имена полей, по которым построен индекс. Если в индексе используется несколько полей, то их имена разделяются точкой с запятой.
 
Свойство options типа TIndexOption содержит параметры индекса, заданные при его создании.
 
Примеры

В форме расположены следующие компоненты: сетка DBGrid, в которой отображаются записи таблицы БД, два списка ListBox с соответствующими надписями, а также две кнопки Button. При нажатии кнопки Индексы (Button1) в список ListBox1 загружается список индексов, определенных для набора данных Table1, а в список ListBox2 список полей, образующих эти индексы. Так как компонент Table1 связан с таблицей Paradox, то имя главного индекса, построенного по полю Name, содержит пустую строку.
 
Обработчик события нажатия кнопки Button1 выглядит так:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
for (int n = 0; n<Table1->IndexDefs->Count;n++)
{
ListBox1->Items->Add(Table1->IndexDefs->Items[n]->Name);
ListBox2->Items->Add(Table1->IndexDefs->Items[n]->Fields);
}
}
Для получения списка имен индексов можно использовать метод класса TTable:
void __fastcall GetlndexNames(Classes::TStrings* List);
Oн возвращает список имен индексов через параметр List, в качестве которого можно использовать любой объект типа TStrings.
 
Например, получение списка имен индексов в программе может выглядеть так:
ListBox1->Items->Clear();
Table1->GetIndexNames(ListBox1->Items);
Для добавления и удаления динамических индексов (задаваемых на этапе выполнения приложения) можно использовать методы Add и clear класса TIndexDefs. Метод HIDESBASE void __fastcall Add(const AnsiString N, const AnsiString F, TIndexOptions Options); добавляет новый индекс. Параметры этого метода (кроме того, что число их на единицу меньше) не отличаются от соответствующих параметров метода AddIndex набора данных Table, однако для метода Add не требуется перевода таблицы в режим монопольного доступа, что делает его использование более удобным.
Динамические индексы действуют только при выполнении приложения, в файле таблицы не сохраняются и поэтому не требуют перевода таблицы в режим монопольного доступа. Более того, при выполнении метода Update класса TIndexDefs происходит обновление текущего списка индексов. При этом динамические индексы заменяются индексами из файла таблицы.
Для таблиц Paradox при определении ключа (главного индекса) имя индекса не задается, т.к. он не именуется.
 
Метод clear удаляет все индексы, содержащиеся в списке.
 
Вот как удаление и добавление динамических индексов к таблице реализуется в программе:
Table1->indexDefs->Clear();
Tablе1->IndexDefs->Add(" " , "Name", TIndexOptions() << ixPrirnary << ixUnique);
Table1->indexDefs->Add("indNP","Name;Post",TIndexOptions() << ixDescending << ixCaseInsensitive);
В этом примере из набора данных Table1, связанного с таблицей Paradox, удаляются все динамические индексы и создаются два новых: первичный индекс, построенный по полю Name, и вторичный индекс indNP, построенный по полям Name и Post.
 
Ряд методов класса TindexDefs предназначен для поиска индексов в списке, например, IndexOf, Find и FindlndexForFields. Их удобно использовать в случае, когда индексы или их поля вводит пользователь на этапе выполнения приложения. Перед использованием таких индексов целесообразно проверять, существуют ли они в списке индексов, т.к. в противном случае может возникнуть исключение.
 
Функция int __fastcall IndexOf (const AnsiString AName); осуществляет поиск индекса по имени, заданному параметром AName. В качестве результата возвращается номер индекса в свойстве items. В случае неудачного поиска возвращается значение -1.
 
Рассмотрим пример поиска индекса:
void __fastcall TForm1::Button4Click(TObject *Sender)
{
int n=Table1->IndexDefs->lndexOf(Edit1->Text);
if (n == -1)
{
MessageDlg("Индекс отсутствует!", mtlnformation, TMsgDlgButtons() << mbOK, 0);
if (Edit1->CanFocus())
Edit1->SetFocus();
}
Edit1->Text=IntToStr(n);
Здесь при нажатии кнопки Button4 выполняется проверка существования индекса, имя которого введено в поле ввода Edit1. При отсутствии в наборе данных Table1 указанного индекса выдается сообщение об ошибке, и фокус ввода устанавливается на Edit1. В любом случае в поле ввода Edit1 отображается результат обращения к функции indexof.
 
Функция TlndexDef* fastcall FindlndexForFields(const AnsiString Fields); осуществляет поиск индекса по списку полей, заданному параметром Fields. В случае успешного поиска функция возвращает информацию об индексе, если индекс отсутствует, то генерируется исключение.
Если не найден индекс, поля которого полностью совпадают с заданными, но есть индексы, которые включают в себя все заданные поля, то в качестве результата возвращается первый такой индекс.
Отметим еще раз, что при запуске приложения информация об индексах таблицы учитывается с диска из соответствующих индексных файлов. При изменении динамических индексов в процессе выполнения приложения, с помощью методов Add и clear класса TIndexDefs содержимое индексных файлов остается прежним. Если же динамические индексы меняются при выполнении приложения с помощью методов AddIndex и DeleteIndex, предполагающих монопольное использование таблицы, то содержимое индексных файлов изменяется соответствующим образом.
 
Свойство StoreDefs типа bool класса TTable указывает, остаются ли определения полей таблицы и индексов с модулем данных или формы. Если это свойство имеет значение true, то определения полей таблицы и индексов хранятся вместе с модулем данных или формы. Установка свойству StoreDefs значения true означает, что метод CreateTable класса TTable реализуется как одношаговая процедура, которая создает поля, индексы и ограничения значений при выполнении приложения. По умолчанию свойство StoreDefs имеет значение false, оно принимает значение true, когда FieldDefs или IndexDefs обновляются или редактируются вручную. Чтобы предотвратить сохранение отредактированных или импортированных определений нужно установить свойству storeDefs значение false.
Если заметили ошибку, выделите фрагмент текста и нажмите Ctrl+Enter

Добавить комментарий


Защитный код Обновить