Автор работы: Пользователь скрыл имя, 26 Января 2013 в 14:13, лекция
Программирование баз данных - очень большой и серьезный раздел самого что ни на есть практического программирования. На предыдущем курсе "Введение в программирование на Delphi" мы лишь коснулись этой темы, затронули даже не верхушку айсберга под названием Базы Данных, а только его макушку. Между тем, многие программисты большую часть своего времени тратят именно на проектирование баз данных и разработку приложений, работающих с ними. Это неудивительно - в настоящее время каждая государственная организация, каждая фирма или крупная корпорация имеют рабочие места с к
Рис. 2.11. Окно связей
Здесь в поле Detail Fields нужно выбрать поле, по которому будет осуществляться связь, в нашем случае это поле "Сотрудник". В поле Master Fields выбираем ключевое поле "Ключ". Затем нажимаем кнопку Add и кнопку OK. Связь установлена.
При установке связей главный / подчиненный важно начинать вести линию с главной таблицы к подчиненной. Если бы мы сделали иначе, то главной таблицей стала бы TAdres. Такую же связь установите и с остальными таблицами. Просто, не правда ли?
Сохраните проект, скомпилируйте его и запустите на выполнение. Если в сетках главного окна вы видите открытые таблицы, то все хорошо. Если нет, возможно, при изменении настроек ваши таблицы закрылись. В таком случае закройте программу (но не проект!), выделите таблицы, и их свойству Active снова присвойте значение True. Таблицы должны появиться в сетках главного окна, даже на этапе проектирования.
Пойдем дальше. Теперь нам нужно сделать окно редактора данных. Создайте новую форму (File -> New -> Form). Ее свойство Name переименуйте в fEditor, а при сохранении формы дайте модулю имя Editor. Командой File -> Use Unit подключите к форме модуль данных DM. Теперь нам нужно установить на форму такие компоненты:
Рис. 2.12. Окно редактора данных
Здесь я поступил следующим образом: установил на форму четыре панели GroupBox с вкладки Standard, на каждую таблицу свой GroupBox. Почему я так поступил, станет понятно позже. Займемся первой таблицей. В свойстве Caption компонента GroupBox впишите "Личные данные", это название отразится в заголовке панели. Далее на эту панель следует установить восемь компонентов DBEdit с вкладки DataControls палитры компонентов, два DBCheckBox для редактирования логических данных, и один компонент DBComboBox для списка. Поясняющие компоненты Label установите и настройте самостоятельно. Немного доработаем компонент DBComboBox. Щелкните дважды по его свойству Items, открыв редактор. В нем введите две строки:
муж
жен
Сохраните текст, нажав кнопку ОК. Теперь пользователь сможет указать пол сотрудника, выбрав нужную строку из списка.
Для таблицы Doljnost все еще проще: на панели GroupBox всего два компонента DBEdit и два поясняющих Label.
Для таблицы Adres используйте три DBEdit.
А вот для таблицы Telephones понадобится один DBEdit, один DBComboBox, сетка DBGrid и кнопка BitBtn. Сетка нужна для контроля введенных телефонов, ведь здесь связь один-ко-многим, и телефонов может быть несколько. В редакторе Items компонента DBComboBox введите три строки:
Рабочий
Домашний
Мобильный
Теперь займемся подключением компонентов контроля. Удерживая <Shift>, выделите все компоненты контроля на первой панели (все компоненты, кроме Label). В их свойстве DataSource выберите fDM.DSLichData, подключив компоненты к нужному набору данных (таблице). Снимите общее выделение, и выделите первый DBEdit. В его свойстве DataField выберите поле "Фамилия". Это свойство подключает выбранный компонент к определенному полю таблицы. Таким же образом подключите к соответствующим полям остальные компоненты. Затем подключайте компоненты других таблиц, каждое к своей таблице и к соответствующему полю. Сетка DBGrid подключается к fDM.DSTelephones, и не имеет поля, разумеется. Она отображает все видимые поля таблицы.
В правой нижней части для удобства пользователя я установил навигационный компонент DBNavigator с вкладки Data Controls. Этот компонент предназначен для перемещения по записям, включения режима редактирования записи, сохранения или отмены сделанных изменений, добавления новой записи или удаления существующей. В его свойстве DataSource я выбрал fDM.DSLichData, чтобы подключить компонент к главной таблице. Нам нужна от этого компонента только возможность перехода на начало или конец таблицы, на следующую или предыдущую запись. Поэтому раскройте его свойство VisibleButtons (видимость кнопок компонента) и переведите в False все кнопки, кроме nbFirst, nbPrior, nbNext и nbLast. Нажатие на эти кнопки приведет к вызову соответствующих методов компонента ADOTable. Эти методы делают следующее:
First - переход на первую запись таблицы.
Prior - переход на предыдущую запись.
Next - переход на следующую запись.
Last - переход на последнюю запись.
Когда у DBNavigator останется всего четыре кнопки, эти кнопки окажутся вытянутыми. Уменьшите ширину компонента, чтобы кнопки приняли более привычный вид.
Теперь пришло время объяснить, почему я поместил компоненты на панели GroupBox, и почему для каждой таблицы сделал отдельную панель. Если вы прошли предыдущий курс "Введение в программирование на Delphi", то знаете, что измененная запись в таблице сохраняется в трех случаях:
Когда мы, заполнив одну таблицу, перейдем к другой, то в первой таблице запись еще не будет сохранена. Поле "Ключ" у нас автоинкрементное, на него завязаны остальные таблицы. До тех пор, пока мы не сохраним запись, в этом поле не будет никакого значения. Следовательно, данные в других таблицах не смогут привязаться к какой-то записи главной таблицы. Поэтому выделите первый GroupBox, и дважды щелкните по событию onExit на вкладке Events инспектора объектов. Это событие происходит всякий раз, когда пользователь перейдет к другой панели GroupBox, либо к кнопкам, расположенным в нижней части окна. В сгенерированной процедуре впишите код:
{Вышли из редактирования LichData}
procedure TfEditor.GroupBox1Exit(Sender: TObject);
begin
if fDM.TLichData.Modified then
fDM.TLichData.Post;
end;
Свойство Modified компонента ADOTable имеет логический тип - в нем содержится True, если данные были изменены, и False в противном случае. Метод Post этого компонента, как уже упоминалось, сохраняет измененную запись таблицы. При этом в поле "Ключ" попадет присвоенное автоматически значение. Таким образом, введенный код означает, что если запись была изменена, то следует ее сохранить. Сгенерируйте событие onExit для оставшихся панелей GroupBox и таким же образом сохраните изменения записей в соответствующих таблицах.
Далее сгенерируйте событие нажатия на кнопку "Добавить" в GroupBox с телефонными данными. Этой кнопкой мы будем добавлять новые записи в таблицу, ведь один сотрудник может иметь более одного телефона. Код в процедуре будет такой:
if fDM.TTelephones.Modified then
fDM.TTelephones.Post;
fDM.TTelephones.Append;
DBEdit14.SetFocus;
Вначале мы сохраняем измененные значения, если они были. Затем методом Append мы добавляем в таблицу новую запись. Добавить новую запись можно двумя методами:
После добавления новой записи таблица уже будет в режиме редактирования, поэтому можно не вызывать метод Edit, который переводит таблицу в этот режим. Далее мы переводим фокус ввода на DBEdit с телефонными номерами, чтобы пользователю не пришлось делать это самому.
В процедуре нажатия на кнопку "Сохранить и выйти" код простой:
if fDM.TLichData.Modified then
fDM.TLichData.Post;
if fDM.TDoljnost.Modified then
fDM.TDoljnost.Post;
if fDM.TAdres.Modified then
fDM.TAdres.Post;
if fDM.TTelephones.Modified then
fDM.TTelephones.Post;
Close;
Здесь мы лишь сохраняем изменения во всех таблицах, если они были, и закрываем окно. Напоследок у нас осталась кнопка "Добавить сотрудника". Что мы должны сделать, если пользователь нажмет на эту кнопку? Добавить новую запись в каждую таблицу и перевести курсор в первый DBEdit, в котором редактируется фамилия. Это и делаем:
fDM.TLichData.Append;
fDM.TDoljnost.Append;
fDM.TAdres.Append;
fDM.TTelephones.Append;
DBEdit1.SetFocus;
С этой формой мы закончили, переходим к главной форме. Не забывайте время от времени сохранять проект. Если вы еще не подключили модуль Editor к главной форме командой File -> Use Unit, то сделайте это сейчас, чтобы можно было вызывать окно редактора из главной формы. Начнем с кнопки "Новый сотрудник". Как и в предыдущем примере, нам потребуется добавить новую запись в каждую таблицу, после чего открыть окно редактора:
fDM.TLichData.Append;
fDM.TDoljnost.Append;
fDM.TAdres.Append;
fDM.TTelephones.Append;
fEditor.ShowModal;
Сгенерируйте процедуру onClick для кнопки "Редактировать". Тут будет лишь одна строчка кода:
fEditor.ShowModal;
В результате откроется окно редактора, и компоненты будут отображать данные текущей записи. Предположим, пользователю будет удобней дважды щелкнуть по записи в верхней сетке DBGrid, чем нажимать кнопку. Поэтому выделите сетку с главной таблицей и сгенерируйте для нее событие onDBLClick. Там введите такую же строчку кода.
Блок поиска по фамилии оставим на следующую лекцию и перейдем к программированию радиокнопок. По нашему замыслу, при открытии программы в верхней сетке DBGrid будут отображаться данные из главной таблицы, а в нижней - из таблицы Adres. Также будет выделена радиокнопка с надписью "Адрес". Если пользователю захочется посмотреть должность или телефоны текущего сотрудника, он будет щелкать соответствующую радиокнопку, и эти данные должны быть отображены в нижней DBGrid. Выделите первую радиокнопку с надписью "Адрес" и сгенерируйте для нее событие onClick, которое будет возникать, когда пользователь щелкнет по ней. В процедуре этого события впишите следующий код:
if RadioButton1.Checked then
DBGrid2.DataSource := fDM.DSAdres;
Здесь мы проверили, включена ли данная радиокнопка. Если да, то мы меняем связь нижней сетки DBGrid и подключаем ее к таблице Adres. Ведь связь сетки с таблицей осуществляется через соответствующий компонент DataSource, а у нас их четыре. Подключаясь то к одному, то к другому DataSource, мы можем программно менять отображенную в сетке таблицу.
Для события onClick радиокнопки с надписью "Телефоны" код будет таким:
if RadioButton2.Checked then
DBGrid2.DataSource := fDM.DSTelephones;
А для события onClick радиокнопки с надписью "Должность", соответственно, код будет следующим:
if RadioButton3.Checked then
DBGrid2.DataSource := fDM.DSDoljnost;
Таким образом, в нижней сетке мы отображаем то одну, то другую подчиненную таблицу, и всякий раз в этих таблицах будут показаны данные текущего сотрудника. Вот и весь код! Сохраните проект и скомпилируйте его. На следующей лекции мы будем изучать методы поиска и фильтрации, поэтому введите в базу данные десятка на два -
3.
Лекция: Поиск, фильтрация и индексация
таблиц: версия для печати и PDA
На этой лекции вы познакомитесь с различными
методами поиска нужной записи в таблице,
с применением фильтрации записей, удовлетворяющих
нужному условию, с использованием индексных
полей для сортировки данных в возрастающем
и в убывающем порядке.
Ознакомление с механизмами поиска данных, фильтрации записей и использование индексов для сортировки.
В программах, работающих с базами данных, часто используют поиск данных. Для чего еще нужны базы данных, как не для этого? Самый простой, но в то же время и самый медленный, "тяжеловесный" поиск, это, пожалуй, последовательный перебор. Вы переходите на первую запись таблицы, создаете цикл, который длится до последней записи, и внутри этого цикла проверяете необходимое условие. Также можно делать и обратный перебор, от последней записи к первой. В таблице 3.1 приведены все свойства и методы наборов данных (TTable/ADOTable, TQuery/ADOQuery), которые могут быть использованы при организации последовательного перебора:
Таблица 3.1. Свойства и методы набора данных, которые могут быть задействованы при последовательном переборе | |
Свойства и методы |
Описание |
Eof |
Свойство логического типа. Принимает значение True, если достигнут конец таблицы, или если таблица пуста, и False в противном случае. |
Bof |
Свойство логического типа. Принимает значение True, если достигнуто начало таблицы, и False в противном случае. |
Next |
Метод. Делает текущей следующую запись набора данных. |
Prior |
Метод. Делает текущей предыдущую запись набора данных. |
First |
Метод. Делает текущей первую запись набора данных. |
Last |
Метод. Делает текущей последнюю запись набора данных. |
Пример:
//перешли на первую запись:
fDM.TLichData.First;
//делать, пока не конец таблицы:
while not fDM.TLichData.Eof do begin
if fDM.TLichData['Фамилия'] = 'Иванов' then
break; //нашли нужную запись, и вышли из цикла
fDM.TLichData.Next; //иначе перешли на следующую запись
end; //while
Как видно из примера, мы делаем прямой последовательный перебор от первой записи до последней. Получить или изменить значение нужного поля можно, указав имя поля в квадратных скобках после имени набора данных. Например:
Edit1.Text := fDM.TLichData['Фамилия']; //получили значение
fDM.TLichData['Фамилия']:= Edit1.Text; //изменили значение
Приведенный пример поиска нужной записи допустим, если в таблице имеется не более сотни-другой записей, а условная проверка достаточно сложна. Но обычно программисты этот способ не используют, или используют только в крайнем случае. Далее рассмотрим другие способы поиска.
Метод Locate ищет первую запись, удовлетворяющую условию поиска. Если запись найдена, метод делает ее текущей и возвращает True. В противном случае метод возвращает False и курсор не меняет положения. Поле, по которому ведется поиск, не обязательно должно быть индексировано. Однако если поле индексировано, то метод ищет запись по индексу, что значительно ускоряет поиск. Поиск может вестись как по одному полю, так и по нескольким полям. Метод имеет три параметра:
function Locate (const KeyFields: String; const KeyValues: Variant;
Options: TLocateOptions) : Boolean;
Параметр KeyFields задает поле или список полей, по которым ведется поиск. Если имеется несколько полей, их разделяют точкой с запятой.
Параметр KeyValues является вариантным массивом, в котором задаются критерии поиска. При этом первое значение KeyValues ставится в соответствие с первым полем, указанным в KeyFields. Второе - со вторым, и так далее.
Третий параметр Options позволяет задать некоторые опции поиска:
Примеры использования метода Locate:
Table1.Locate('Фамилия', Edit1.Text, []);
Table1.Locate('Фамилия;Имя',
VarArrayOf(['Иванов', 'Иван']), [loCaseInsensitive]);
Как видно из примера, если для поиска вы используете одно поле, то значение может передаваться напрямую из компонента Edit. Если же вы используете список полей, то должны передать в метод массив вариантов, в которых содержатся искомые значения, по одному на каждое поле. При установке компонента ADOTable в раздел uses прописывается модуль ADODB, который содержит описания всех свойств, методов и событий компонента. Желательно использовать метод в том модуле, где установлен этот компонент.