Главная » Delphi » Работа с наборами данных

0

Набор данных (dataset) — это  коллекция строк  и столбцов данных.  Каждый  столбец (column) содержит данные  одинакового типа,  а каждая  строка (row)  представляет со бой набор  данных каждого из типов  данных столбцов. Столбец иногда  называют полем (field), а строку — записью (record). Библиотека VCL инкапсулирует набор  данных  в аб страктном классе по имени  TDataSet, который обладает множеством свойств и мето дов, необходимых для манипулирования и перемещения по набору  данных.  От этого базового класса происходят все остальные классы,  предназначенные для работы с различными типами наборов данных.

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

•  Набор данных (dataset) — это набор  отдельных записей данных.  Каждая  запись  со держит несколько полей.  Каждое поле может содержать различные типы данных (целые числа,  строковые значения, десятичные числа,  графику  и т.д.).  Наборы данных представлены в библиотеке VCL абстрактным классом TDataSet.

•  Таблица (table) — это  специальный тип  набора данных.  Как правило, она  пред ставляет собой  файл,  содержащий записи и физически хранящийся где нибудь на  диске.  В библиотеке VCL таблицы инкапсулируют классы  TTable, TADO- Table, TSQLTable и TIBTable.

•  Запрос (query) —  это  специальный тип  набора данных.  Запрос можно  рассмат ривать как команду, которую  должен  выполнить сервер баз данных.  Вследствие таких  команд  может  быть  возвращен результат (result). Если возвращается на бор данных, то он оформляется в виде виртуальной (созданной в памяти) таб лицы,  называемой результатом запроса (resultset). Результат  запроса представля ет собой  специальный набор  данных, который инкапсулирован в классах TQuery, TADOQuery, TSQLQuery и TIBQuery.

НА ЗАМЕТКУ

Как уже говорилось, настоящая книга подразумевает наличие у читателя определен- ных знаний в области баз данных. Эта глава не является учебником для начинающих программистов баз данных, и мы полагаем, что термины вышеприведенного списка читателю уже знакомы. В противном случае, если такие термины, как база данных, таблица и индекс, понятны не до конца, то прежде чем приступать к изучению на- стоящей главы, рекомендуем обратиться к литературе, посвященной основам работы с базами данных.

Как открыть и закрыть набор данных

Прежде чем выполнять манипуляции с набором данных, его необходимо открыть. Для этого  достаточно вызвать метод Open(), как показано в приведенном ниже фрагменте кода:

Table1.Open;

Это эквивалентно присвоению свойству Active набора данных значения True:

Table1.Active := True;

Второй способ  является менее  накладным, поскольку  метод  Open() в конечном счете  также  присваивает свойству  Active значение True. Однако потери при  этом настолько незначительны, что об этом не стоит и беспокоиться.

Открытым  набором  данных  можно  свободно  манипулировать.  По  завершении  ис

пользования набора данных его необходимо закрыть, вызвав для этого метод Close():

Table1.Close;

Альтернативный способ  закрыть набор  данных  заключается в присвоении его свойству Active значения False:

Table1.Active := False;

CОВЕТ

При взаимодействии с SQL-сервером соединение с базой данных должно быть уста- новлено при первом открытии набора данных в этой базе. При закрытии последнего набора данных в базе установленное с ней соединение будет закрыто. Открытие и за- крытие подобных соединений создает значительную нагрузку на систему. Если откры- тие и закрытие соединений с базой данных SQL-сервера приходится выполнять слиш- ком часто, то благоразумней воспользоваться компонентом TDatabase, который по- зволит избежать этих проблем. Более подробная информация о компоненте TDatabase приведена в следующей главе.

Листинг 7.1 во всех подробностях демонстрирует то, как необходимо открывать и закрывать различные типы наборов данных.

Листинг 7.1. Как открыть и закрыть набор данных

unit MainFrm;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics,

Controls, Forms, Dialogs, FMTBcd, DBXpress, IBDatabase, ADODB,

DBTables, DB, SqlExpr, IBCustomDataSet, IBQuery, IBTable,

StdCtrls;

type

TForm1 = class(TForm)

SQLDataSet1: TSQLDataSet;SQLTable1: TSQLTable; SQLQuery1: TSQLQuery;

ADOTable1: TADOTable; ADODataSet1: TADODataSet; ADOQuery1: TADOQuery;

IBTable1: TIBTable; IBQuery1: TIBQuery; IBDataSet1: TIBDataSet;

Table1: TTable; Query1: TQuery;

SQLConnection1: TSQLConnection; Database1: TDatabase; ADOConnection1: TADOConnection; IBDatabase1: TIBDatabase; Button1: TButton;

Label1: TLabel; Button2: TButton; IBTransaction1: TIBTransaction;

procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure FormClose(Sender: TObject;

var Action: TCloseAction);

procedure Button2Click(Sender: TObject);

private

{ Закрытые объявления }

procedure OpenDatasets;

procedure CloseDatasets;

public

{ Открытые объявления }

end;

var

Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);

begin

IBDatabase1.Connected        := True;

ADOConnection1.Connected := True;

Database1.Connected          := True;

SQLConnection1.Connected := True;

end;

procedure TForm1.Button1Click(Sender: TObject);

begin

OpenDatasets;end;

procedure TForm1.FormClose(Sender: TObject;

var Action: TCloseAction);

begin CloseDatasets; IBDatabase1.Connected  := false; ADOConnection1.Connected := false; Database1.Connected   := false; SQLConnection1.Connected := false;

end;

procedure TForm1.CloseDatasets;

begin

// Отключиться от набора данных dbExpress SQLDataSet1.Close; // или .Active := false; SQLTable1.Close;        // или .Active := false; SQLQuery1.Close; // или .Active := false;

// Отключиться от набора данных ADO ADOTable1.Close;   // или .Active := false; ADODataSet1.Close;      // или .Active := false; ADOQuery1.Close; // или .Active := false;

// Отключиться от набора данных Interbase Express

IBTable1.Close;

//

или .Active := false;

IBQuery1.Close;

//

или .Active := false;

IBDataSet1.Close;

//

или .Active := false;

// Отключиться от набора данных BDE Table1.Close;      // или .Active := false; Query1.Close;         // или .Active := false;

Label1.Caption := ‘Datasets are closed.’ end;

procedure TForm1.OpenDatasets;

begin

// Подключиться к набору данных dbExpress SQLDataSet1.Open;  // или .Active := true; SQLTable1.Open;        // или .Active := true; SQLQuery1.Open;    // или .Active := true;

// Подключиться к набору данных ADO ADOTable1.Open;    // или .Active := true; ADODataSet1.Open;      // или .Active := true; ADOQuery1.Open;    // или .Active := true;

// Подключиться к набору данных Interbase Express IBTable1.Open;   // или .Active := true; IBQuery1.Open;    // или .Active := true;IBDataSet1.Open;    // или .Active := true;

// Подключиться к набору данных BDE Table1.Open; // или .Active := true; Query1.Open;                     // или .Active := true;

Label1.Caption := ‘Datasets are open.';

end;

procedure TForm1.Button2Click(Sender: TObject);

begin

CloseDatasets;

end;

end.Этот пример содержится на прилагаемом CD. При  установке соединений с базами данных  могут  возникнуть некоторые  проблемы, поскольку  пример был  создан  для конкретной машины. Чтобы он стал работоспособен на другом компьютере, необхо димо  установить параметры соединения, соответствующие конкретной машине.  Од нако целью настоящего примера была демонстрация способов подключения к раз личным типам наборов данных.

Навигация по набору данных

Класс TDataSet содержит несколько простых методов для работы с записями. Ме тоды First() и Last() перемещают указатель  текущей  записи к первой и последней записям в наборе данных  соответственно, а методы  Next() и Prior() —  на одну за пись вперед  или назад. Методу MoveBy() передается параметр типа  Integer, в кото ром указывается, на какое  количество записей следует переместить указатель  вперед или назад.

Свойства  BOF, EOF и циклы

Свойства BOF и EOF класса TDataSet имеют  тип Boolean и показывают, является ли текущая  запись  первой или  последней в наборе данных.  Например, необходимо выполнить выборку  каждой  записи набора данных, вплоть  до последней. Эту простую задачу можно  решить с помощью цикла while, в котором выборка записей будет про должаться до тех  пор,  пока  свойство EOF не примет значение True, как показано в приведенном ниже фрагменте кода:

Table1.First;                   // Переход к началу набора данных

while not Table1.EOF do begin // Перебор всех записей в таблице

{ Выполнение обработки текущей записи }

Table1.Next;                    // Переход к следующей записи

end;

CОВЕТ

Вызывайте метод Next() только внутри цикла while-not-EOF, иначе приложение может попасть в бесконечный цикл.Избегайте использования цикла  repeat..until для  выполнения действий над набором данных.  Следующий  код на первый взгляд  выглядит вполне нормально, но если попытаться выполнить его с пустым набором данных, то может  возникнуть про блема,  поскольку   процедура DoSomeStuff() будет  выполняться по  крайней мере один раз, независимо от того, содержит набор  данных записи  или нет.

repeat DoSomeStuff; Table1.Next;

until Table1.EOF;

Поскольку цикл while-not-EOF выполняет проверку условия вначале, то при ис

пользовании этой конструкции описанной выше проблемы не возникает.

Листинг 7.2 содержит пример, иллюстрирующий возможности навигации по раз

личным типам наборов данных.

Листинг 7.2. Навигация по различным типам наборов данных

unit MainFrm;

interface uses

Windows, Messages, SysUtils, Variants, Classes, Graphics,

Controls, Forms, Dialogs, FMTBcd, DBXpress, IBDatabase, ADODB,

DBTables, DB, SqlExpr, IBCustomDataSet, IBQuery, IBTable,

StdCtrls, Grids, DBGrids, ExtCtrls;

type

TForm1 = class(TForm)

SQLTable1: TSQLTable;

ADOTable1: TADOTable;

IBTable1: TIBTable;

Table1: TTable;

SQLConnection1: TSQLConnection; Database1: TDatabase; ADOConnection1: TADOConnection; IBDatabase1: TIBDatabase; Button1: TButton;

Label1: TLabel; Button2: TButton; IBTransaction1: TIBTransaction; DBGrid1: TDBGrid;

DataSource1: TDataSource; RadioGroup1: TRadioGroup; btnFirst: TButton; btnLast: TButton;

btnNext: TButton;

btnPrior: TButton;

procedure FormCreate(Sender: TObject);

procedure Button1Click(Sender: TObject);procedure FormClose(Sender: TObject;

var Action: TCloseAction);

procedure Button2Click(Sender: TObject);

procedure RadioGroup1Click(Sender: TObject);

procedure btnFirstClick(Sender: TObject);

procedure btnLastClick(Sender: TObject);

procedure btnNextClick(Sender: TObject);

procedure btnPriorClick(Sender: TObject);

procedure DataSource1DataChange(Sender: TObject;

Field: TField);

private

{ Закрытые объявления }

procedure OpenDatasets;

procedure CloseDatasets;

public

{ Открытые объявления }

end;

var

Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);

begin

IBDatabase1.Connected        := True;

ADOConnection1.Connected := True;

Database1.Connected          := True;

SQLConnection1.Connected := True;

Datasource1.DataSet := IBTable1; OpenDatasets;

end;

procedure TForm1.Button1Click(Sender: TObject);

begin

OpenDatasets;

end;

procedure TForm1.FormClose(Sender: TObject;

var Action: TCloseAction);

begin CloseDatasets; IBDatabase1.Connected  := false; ADOConnection1.Connected := false; Database1.Connected   := false; SQLConnection1.Connected := false;

end;

procedure TForm1.CloseDatasets;

begin

// Отключиться от набора данных dbExpress dataset

SQLTable1.Close;        // или .Active := false;

// Отключиться от набора данных ADO dataset

ADOTable1.Close;        // или .Active := false;

// Отключиться от набора данных Interbase Express dataset

IBTable1.Close;        // или .Active := false;

// Отключиться от набора данных BDE datasets

Table1.Close;         // или .Active := false;

Label1.Caption := ‘Datasets are closed.’ end;

procedure TForm1.OpenDatasets;

begin

// Подключиться к набору данных dbExpress

SQLTable1.Open;        // или .Active := true;

// Подключиться к набору данных ADO ADOTable1.Open;    // или .Active := true;

// Подключиться к набору данных Interbase Express

IBTable1.Open;         // или .Active := true;

// Подключиться к набору данных BDE Table1.Open; // или .Active := true;

Label1.Caption := ‘Datasets are open.';

end;

procedure TForm1.Button2Click(Sender: TObject);

begin

CloseDatasets;

end;

procedure TForm1.RadioGroup1Click(Sender: TObject);

begin

case RadioGroup1.ItemIndex of

0: Datasource1.DataSet := IBTable1;

1: Datasource1.DataSet := Table1;

2: Datasource1.DataSet := ADOTable1;

end; // case

end;

procedure TForm1.btnFirstClick(Sender: TObject);

begin

DataSource1.DataSet.First;

end;procedure TForm1.btnLastClick(Sender: TObject);

begin

DataSource1.DataSet.Last;

end;

procedure TForm1.btnNextClick(Sender: TObject);

begin

DataSource1.DataSet.Next;

end;

procedure TForm1.btnPriorClick(Sender: TObject);

begin

DataSource1.DataSet.Prior;

end;

procedure TForm1.DataSource1DataChange(Sender: TObject; Field: TField);

begin

btnLast.Enabled := not DataSource1.DataSet.Eof;

btnNext.Enabled := not DataSource1.DataSet.Eof;

btnFirst.Enabled := not DataSource1.DataSet.Bof;

btnPrior.Enabled := not DataSource1.DataSet.Bof;

end;

end.

В этом примере переключатель TRadioGroup используется для того,  чтобы  позво лить пользователю выбирать один из трех типов  баз данных.  Кроме  того,  обработчик события OnDataChange демонстрирует возможность применения свойств  BOF и EOF для того,  чтобы  в зависимости от их состояния разрешать или запрещать использова ние кнопок. Обратите внимание: для навигации по набору данных  применяются оди наковые методы, независимо от конкретного типа набора данных.

НА ЗАМЕТКУ

Имейте в виду: в данном примере компонент dbExpress не применяется. Это связано с тем, что dbExpress предназначен для односторонних наборов данных (unidirectional dataset), по которым можно перемещаться только в одном направлении и получать доступ только для чтения. Фактически, если попытаться подключать к набору данных dbExpress двунаправленный компонент навигации (типа TDBGrid), то произойдет ошибка. Для управления односторонними наборами данных необходим специальный подход. Более подробная информация по этой теме приведена в главе 8, “Применение dbExpress при разработке баз данных”.

Источник: Тейксейра, Стив, Пачеко, Ксавье.   Borland Delphi 6. Руководство разработчика. : Пер.  с англ. — М. : Издательский дом “Вильямс”, 2002. —  1120 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии