Показаны сообщения с ярлыком База данных. Показать все сообщения
Показаны сообщения с ярлыком База данных. Показать все сообщения

вторник, 20 марта 2012 г.

Урок 36. Продолжаем разговор...

Именно так любил приговаривать очаровательный мультяшный герой по имени Карслон, который живет на крыше...

Прежде, чем углубиться дальше в лес Delphi и не только,  я бы хотел оживить некоторые пункты меню проекта "Расходы".

Шаг 1. Пункт меню "О программе"


Когда-то, в уроке №13, я рассказал о том, как сделать компонент "О программе". Вам придется его немного подправить :-) и разместить на форме MainFrm, а затем назначить соответствующему пункту меню вот такой простой обработчик:


procedure TMainFrm.N_AboutClick(Sender: TObject);
begin
  PrDAboutBoxDlg1.Execute;
end;


Наделите компонент следующими свойствами:



Щаг 2. Никто не обратил внимания, что кнопка Cancel (PrDCancelButton1) на верхней панельке осталась без обработчика. Добавьте обработку действий, когда пользователь ничего не ввел в поля новой записи или передумал добавлять новую запись:


procedure TMainFrm.PrDCancelButton1Click(Sender: TObject);
begin


  // Отказ от редактирования
  ADOTableMain.Cancel;
  DBGridEh1.Enabled:=True;                                   // Переключение грида в режим доступности
  Panel3.Visible:=False;                                            // Скрытие верней панели


end;

Шаг 3. Новый Action Data_Insert, обрабатывающий процесс добавления новой записи, необходимо добавить в список ActionList и подложить его под соответствующие пункты главного меню и PopupMenu:


Обработчик события выполнения экшена:


procedure TMainFrm.Data_InsertExecute(Sender: TObject);
begin


  // Новая запись
  ADOTableMain.Insert;


end;



Внимание! Не забыть вернуться к процедуре:

procedure TMainFrm.Data_SelectMOExecute(Sender: TObject);    // Соответствует N_EditClick
begin
...
  //   Сделать доступным именно Action, а пункты меню станут доступными автоматически
  Data_Insert.Enabled:=True;


Шаг 4. Выбор базы данных

Добавьте Action в категорию Service


Создайте обработчик Action:




procedure TMainFrm.Service_Select_DiskExecute(Sender: TObject);
begin


  // Выбор диска с базой данных
  SetDisk;
  MainConnecting;
  TableActive(True);


  // Инфо на статусбаре
  StatusBarUpdate;


end;

Установите соответствие пункта меню и нового действия.
Данный пункт меню позволит Вам выбрать для просмотра и работы другую базу данных (например, по прошествии года, после архивации базы данных, сохранения ее в другом каталоге).

На этом пока все.
В следующем уроке я предполагаю показать как "перевести" интерфейс программы на другой язык.



понедельник, 26 декабря 2011 г.

Урок 26. Обнуление базы данных


Предыдущий урок был посвящен вопросам подключения к базе данных, расположенной на сменном носителе.
Сегодня я хочу показать, как с использованием компонента TADOCommand вносить изменения в базу данных. Мои не случайные читатели, которые следят за ходом событий, спросят: "Что это ты, Александр Львович, все вокруг да около ходишь? Когда же, наконец, мы двинемся дальше?" А скоро, очень скоро мы продолжим разработку основного алгоритма программы (кстати, Вы не забыли, как она называется и для чего, собственно, она предназначена? :-) ). Я стараюсь сохранить интригу. Да и не интересно будет рассказывать о разных мелочах настройки интерфейса и т.п., когда основной материал останется позади. Так что: терпение, мой друг, терпение...
А сейчас нужно добавить новый Action, создав новую категорию Service. Его свойства показаны на рисунке.
Затем положить на форму компонент TADOCommand с вкладки dbGo панели компонентов. Этот компонент как раз предназначен для того, чтобы выполнять запросы к базе данных, не требующие ответов, т.е. такие, которые видоизменяют информацию в базе данных, но не возвращают пользователю никакого набора строк. В нашем случае, например, по окончании календарного года старые записи становятся не очень-то актуальны. Хранить их нужно (мало ли что?!), а вот таскать везде с собой - вовсе не обязательно. Поэтому и существует необходимость почистить наше хранилище.
И последнее, что нужно сделать - написать обработчик события onExecute, не забыв при этом дать объявление процедуре и "подложить" этот Action под один из пунктов меню "Настройки".
Итак, текст обработчика события onExecute:
procedure TMainFrm.Service_ClearExecute(Sender: TObject);
begin
// Предупреждающий диалог с оператором
MyMessenger.MessageString:='Будет произведена полная очистка базы данных'+CR+'Выполнить?';
MyMessenger.TitleString:='Обслуживание...';
MyMessenger.MessageType:=mtConfirmation;
MyMessenger.Buttons:=[mbYes]+[mbNo];
If MyMessenger.ShowMessage=6
Then
Begin
// Выбор БД и подключение (случае, если необходимые данные не вводились и работа программы только началась)
SetDisk;
MainConnecting;
TableActive(True);
// Подготовка
With ADOCommand1 do
begin
CommandTimeout := 45;
Connection := ADOConnection1;
Prepared := True;
MyMessenger.MessageString:='Можно вычислить остатки на начало или обнулить их'
+CR
+CR
+'Вычислить и запомнить остатки на начало?';
If MyMessenger.ShowMessage=6
Then
Begin                              // Вычисление остатков (заготовка на будущее)
// Подсчет оборотной ведомости и перенос вычисленных остатков - зона нашего ближайшего развития
End
Else                               // Обнуление остатков
begin
// Очистка остатков (значения полей Ost_D и Ost_K таблицы  Accounts будут установлены в ноль)
CommandText:= 'UPDATE Accounts SET Accounts.Ost_D = 0, Accounts.Ost_K = 0';
Execute;
end;
// Очистка главной таблицы (удаление всех записей из таблицы)
CommandText:= 'DELETE FROM Main';
Execute;
// Очистка списка МО (удаление всех записей из таблицы)
CommandText:= 'DELETE FROM MOs';
Execute;// Очистка оборотки (разберем на одном из следующих уроков)
//CommandText:= 'DELETE FROM Oborot';
//Execute;


// Сообщение оператору
MyMessenger.MessageString:='Операция завершена успешно';
MyMessenger.MessageType:=mtInformation;
MyMessenger.Buttons:=[mbOK];
MyMessenger.ShowMessage;
end;
End;
end;

Как видно из текста этой несложной процедуры: один компонент TADOCommand выполняет последовательно несколько запросов: один - на изменение данных в таблице Accouts, остальные - на удаление записей из таблиц. Почему записи не следует удалять из таблицы Accounts? Очень просто: эта таблица содержит план счетов, говоря бухгалтерским языком. Или попросту - условно постоянный набор признаков, который можно использовать из года в год.


В следующем уроке я расскажу о подготовке главной формы к полноценному отображению данных с помощью DBGridEh, а так же поговорим о полях LookUp.


воскресенье, 27 ноября 2011 г.

Урок 25. База данных потерялась?


В предыдущем уроке я остановился на том, что показал один из способов наведения порядка в отображаемой интерфейсом программы таблице, т.е. показал один из способов сортировки получаемых из базы данных записей.
Сегодня мне хотелось бы остановиться вот на каком вопросе: испытания собственной программы я произвожу сам, поэтому сам нахожу ее удобные и не очень места. И вот одним из таких подводных камней мне видится смена буквы съемного носителя. Да-да, мой уважаемый читатель, программу можно носить с собой везде, разместив ее на USB, скажем, носителе, поскольку программа, как Вы уже знаете, использует для собственных настроек файл ini, что многие могут посчитать старомодным, а не реестр операционной системы. Использование реестра ОС - модно и современно, но требует написания инсталлятора. Оставим этот вопрос на будущее. А сейчас попробуем разобраться с такой бедой: сменный диск, подключенный к одному компьютеру, имеет, скажем, букву “Е”, а на другом он становится “F”. Но в строке подключения к базе данных, если кто обратил внимание:
ConnectionString=Provider=Microsoft.Jet.OLEDB.4.0;Data Source=X:\Lessons\...\Les 25\Расходы\Rashod.mdb;...
четко прописана буква диска в абсолютном пути (Data Source=X:).
Как быть? Править вручную файл ini перед использованием программы - занятие скучное и неблагодарное.
Тогда предлагаю использовать следующий алгоритм:
- прочитать строку подключения из файла ini,
- попробовать подсоединиться к базе данных,
- при неудачном подсоединении дать возможность оператору выбрать расположение базы данных, используя стандартное окно диалога,
- записать в файл ini новую строку подключения.
Последую примеру героя М.М. Жванецкого: “Если вопросов нет, я начну”.
Добавьте на форму MainFrm компонент TOpenDialog с палитры компонентов, с вкладки “Dialogs”.
Создайте новую процедуру следующего содержания:
procedure TMainFrm.SetDisk(); // Установка диска с БД
Var
ini: TIniFile;
ConnectionString: String;
MyDir: String;
begin
MyDir:=GetCurrentDir; // Запомнить в переменную путь к текущему директорию
OpenDialog1.Filter:='Файлы базы данных|*.mdb'; // Фильтр для диалога выбора файла (показывать только файлы баз данных Access
// Выбор файла
If not OpenDialog1.Execute // Открытие окна диалога
then // Отмена выбора
begin
exit; // Выход из подпрограммы
end;
ini:=TiniFile.Create(MyDir + '\Rashod.ini'); // Подключение к файлу настроек
MySelect.MySel_Dir:=ExtractFilePath(OpenDialog1.FileName); // Извлечение абсолютного пути к выбранному файлу
ConnectionString:='Provider=Microsoft.Jet.OLEDB.4.0;Data Source='+MySelect.MySel_Dir+'Rashod.mdb;Persist Security Info=False'; // Конструирование строки подключения
Ini.WriteString('General','ConnectionString',ConnectionString); // Запись строки подключения в файл настроек
// Ini.WriteString('General','TempConnectionString',ConnectionString);
ini.Free; // Освобождение памяти
SetCurrentDir(MyDir); // Возврат программы к текущему каталогу
end;
Один тонкий момент есть в этой процедуре, который мне хотелось бы пояснить. Дело в том, что компонент TOpenDialog, устанавливает текущий директорий по понятиям операционной системы. Поэтому, если Вы выбрали какую-то папку с базой данных, отличную от рабочей папки программы, то работа программы нарушится. Следовательно, необходимо запомнить в строковой переменной положение указателя на текущую папку до начала всего действия:
MyDir:=GetCurrentDir;,
а по окончании действия, вернуть его на место:
SetCurrentDir(MyDir);
Не забудьте дать объявление новой процедуры в секции Private описания интерфейса:
procedure SetDisk();
Где должна сработать новая процедура? Конечно же, при создании формы, при обработке события onCreate:
If Not TestConnection
then
SetDisk();
Теперь для тестирования измените вручную путь к базе данных, прописанный в файле ini.
Удачи.

Что же дальше?
На следующем уроке я планирую рассказать, как производится очистка базы данных, удаление всех записей из таблиц или присвоение отдельным полям стартовых (нулевых) значений.


вторник, 11 октября 2011 г.

Урок 20. Подключение к базе данных


Продолжаем разговор о создании программы "Расходы". 


На прошлом уроке я позволил себе лирическое отступление, рассказав о создании заставки к программе.
Но сегодня, мой дорогой читатель,  наступил долгожданный момент, когда речь пойдет о подключении к созданной нами ранее в среде MS Access базе данных Rashod.mdb.
Но, для начала, предлагаю ввести одну переменную типа записи и одну полезную константу в разделе interface:
const CR=#13#10;                   // Константа перевода каретки
Type  TMySelect = record
-  объявление типа запись,  на основе которого будет объявлена переменная,  предназначенная для хранения  выбираемых в процессе работы значений
MySel_ID: Integer;             // Идентификатор выбранной строки
MySel_IDAcc: Integer;          // Идентификатор счета
MySel_AccName: String;         // Наименование счета
MySel_IDMO: Integer;           // Идентификатор мемориального ордера
MySel_MOName: String;          // Наименование мемориального ордера
MySel_Mes: Integer;            // Номер месяца
MySel_IDVal: Integer;          // Идентификатор валюты
MySel_ValName: String;         // Название валюты
MySel_Dir: String;             // Выбранная рабочая папка
MySel_Field: String;           // Имя поля
end;

И пусть это пока не смущает... Пригодится.
Не забудьте добавить объявление переменной:
var  MySelect: TMySelect;
Теперь настало время открыть форму в режиме конструктора и разместить на ней компонент TADOConnection с вкладки dbGO панели инструментов. Этот компонент не единственный, который позволяет связать приложение с базой данных. Есть ряд компонентов сторонних производителей, выполняющий аналогичные функции. Корифеи начнут упрекать меня за выбор этого компонента, но я оправдаюсь следующим:
  • данный компонент входит в стандартную поставку среды разработки (т.е. Вам не придется искать и покупать аналоги сторонних производителей),
  • работа с ним проста и удобна,
  • компонент работает надежно и стабильно.
Измените свойство Login Prompt экземпляра ADOConnection1 компонента TADOConnection на False. Это нужно для того, чтобы при попытке подключения к базе данных не запрашивался пароль и логин. В других задачах Вы можете использовать иные настройки.
Затем, как показано на иллюстрации:
  1. щелкните по кнопке с многоточием в поле ConnectionString, чтобы вызвать редактор строки подключения,
  2. нажмите кнопку "Build" - построить,
  3. выберите драйвер MS Jet, позволяющий коннектиться к базам данных Access,
  4. нажмите кнопку "Далее"
  5. выберите базу данных Rashod.mdb,
  6. нажмите "Проверить соединение",
  7. нажмите "ОК".
Полученную с помощью мастера строку подключения скопируйте целиком в соответствующую строку файла Rashod.ini (см. видео):
[General]
ConnectionString=Provider=Microsoft.Jet.OLEDB.4.0;Data Source=X:\Lessons\InternetBusiness\! VideoLessons\Les 20\Расходы\Rashod.mdb;Persist Security Info=False

Правильно сформированная строка не вызовет ошибки, если свойство Connected элемента ADOConnection1 изменить на True. Если у Вас все получилось, верните этому свойству первоначальное значение.
ВНИМАНИЕ! В финале работы над проектом Вы обязательно удалите строку подключения из свойства ConnectionString!
Но, не сейчас. Она нам еще понадобится, когда мы продолжим разработку и будем наполнять проект таблицами и запросами.
Теперь нам необходимо осуществить программное подключение.
В описании класса формы, в разделе Private, добавим одну процедуру и одну функцию:
private    { Private declarations }
Procedure MainConnecting();
Function TestConnection(): Boolean;
Назначение функции - дать ответ на вопрос: возможно ли подключение к базе данных по заданной в ini файле строке подключения.
Процедура же, после тестирования производит необходимые действия по подключению к базе данных.
Текст функции:
Function TMainFrm.TestConnection(): Boolean;
var  ini: TIniFile;
ConnectionString: String;
begin
Result:=True;                     // Если не произойдет "плохого", то функция вернет это значение
// Подключение и считывание из файла настроек
ini  ini:=TiniFile.Create(GetCurrentDir + '\Rashod.ini');
ConnectionString:=Ini.ReadString('General','ConnectionString','');
ini.Free;
// Проверка, имеется ли подключение? Если да, то - сброс
If ADOConnection1.Connected=True  then    ADOConnection1.Connected:=False;
// Назначение компоненту считанной из файла настроек строки подключения
ADOConnection1.ConnectionString:=ConnectionString;
// Подключение
Try
ADOConnection1.Connected:=true;
Except
ADOConnection1.Connected:=False;     // Если неудача
Result:=False;
End;
end;

Процедура:
Procedure TMainFrm.MainConnecting();
var  ini: TIniFile;
ConnectionString: String;
begin
ini:=TiniFile.Create(GetCurrentDir + '\Rashod.ini');
ConnectionString:=Ini.ReadString('General','ConnectionString','');
ini.Free;
If ADOConnection1.Connected=True  then    ADOConnection1.Connected:=False;
ADOConnection1.ConnectionString:=ConnectionString;
ADOConnection1.Connected:=true;
end;

А теперь, задав для события создания формы (onCreate) процедуру его обработки как показано в прилагаемом видео, запишем в нее следующий текст:
procedure TMainFrm.FormCreate(Sender: TObject);
begin
// Стартовые значения переменным
MySelect.MySel_ID:=0;
MySelect.MySel_IDAcc:=0;
MySelect.MySel_IDMO:=0;
MySelect.MySel_AccName:='';
MySelect.MySel_MOName:='';
MySelect.MySel_Mes:=0;
MySelect.MySel_IDVal:=1;
MySelect.MySel_ValName:='Руб';
If Not TestConnection  then    {некие действия с помощью процедуры SetDisk, разговор о которой в будущем};
MainConnecting;
// далее будет произведено подключение таблиц TableActive(True);
end;
Если Вы скомпилировали проект, и при этом не возникло ошибок, на этом на сегодня все.

Что же дальше?
Короткий разговор о контейнерах и элементах управления главной формы.

пятница, 2 сентября 2011 г.

Урок 18. Создание реляционной БД


Привет.
С Вами Веселов Александр.
В предыдущем уроке я дал краткий обзор возможностей будущей программы и обещал рассказать о создании базы данных. Приступаю без промедления.
- А какие данные удобно и нужно помещать в базу? - спросит меня пытливый читатель и будет прав, подумав: "Неужели, нельзя обойтись электронной таблицей типа Excel?"
Я не скажу в ответ "нет". Вообще, как аксиому, советую принять во внимание следующее: "Для решения той или иной компьютерной задачи, как правило, существует несколько способов". А посему - обойтись-то можно, НО!
И в данной ситуации я не стану, как  прежде, отсылать моего уважаемого читателя к толстым томам, а обобщая собственный опыт и знания, извлеченные из этих томов, укажу на ряд принципов, исходя из которых, формируется база данных:
  1. Принцип. Любую информацию, которую можно упорядочить и представить в виде пронумерованного списка (списков), удобнее хранить в базе данных.
  2. Принцип. Для информации, которую можно выделить по определенному признаку (или набору признаков) должна быть организована отдельная таблица в базе данных.
  3. Принцип. Никакие данные не должны дублировать друг друга (иными словами: каждая цифра должна храниться один раз).
Мой опыт (а начинал я создавать первую базу данных, когда еще о реляциях разговоры только начинались, а споры велись вокруг того, что лучше: способ прямого или последовательного доступа) однозначно указывает мне на предпочтение в использовании реляционной базы данных.
Реляционная база данных - это база данных, между объектами которой (между таблицами) заранее, еще на этапе проектирования устанавливаются определенные отношения (реляции или связи). Что это за волшебные штучки такие, Вы можете подробно узнать из учебников. Простым языком я постараюсь объяснить на примере:
допустим, имеются два списка (таблицы): первый список содержит фамилии сотрудников, второй - зарплату за текущий месяц.
На бумаге (или в Excel) это выглядело бы так:
Таблица 1 - список сотрудников организации:
  1. Иванов
  2. Петров
  3. Сидоров
Таблица 2 - зарплата за текущий месяц:
  1. Петров   30000 р.
  2. Сидоров 20000 р.
(а Иванов ничего не заработал :-) в этом месяце).
Отмечу, что цифры слева в первой и второй таблицах - это просто номера по порядку, номера строк, если хотите. Главное, что каждая строчка имеет уникальный номер. Не возможно сделать еще одну запись за номером 3 в первой таблице и вписать туда фамилию Кузнецов. Мы должны так организовать таблицу, чтобы каждая фамилия имела уникальный, не повторяющийся номер. Такие уникальные номера (идентификаторы или ID) называют ключами.
В таблицах базы данных, исходя из принципа №3, нельзя хранить одну и ту же информацию дважды, поэтому во второй таблице, вместо фамилий нужно подставить, соответствующие им номера строк (коды или ID) из первой таблицы. Тогда вторая таблица, с точки зрения проектировщика базы данных, примет вид:
  1. 2    30000 р.
  2. 3   20000 р.
Так вот одно из назначений реляций в том, чтобы: не дать оператору возможности внести во вторую таблицу данные по несуществующей в первой таблице фамилии, т.е. мы не сможем дополнить вторую таблицу строкой следующего содержания:
3.  4   100 р.,
потому что в первой таблице нет фамилии под номером 4.
Далее, предположим, что Петров уволился с работы. Мы удаляем его фамилию из первой таблицы. Реляционное отношение, установленное между таблицами, не даст нам этого сделать просто так. Ведь, удалив фамилию из списка первой таблицы, нарушится все тот же принцип №3! Поэтому, база данных, в зависимости от того, как мы настроим свойства реляции, либо
  • удалит всю информацию про Петрова (т.е. строчку 1.   2    30000 р.) из второй таблицы (так называемое каскадное удаление данных)
  • либо предложит нам оставить все как есть (тогда проектировщик базы данных должен сам позаботиться о том, чтобы как-то пометить запись про Петрова, чтобы он больше не попадался на глаза в будущем), выдав на экран сообщение о невозможности удаления записи из первой таблицы, так как имеются связанные реляцией записи во второй таблице.
Таким образом, реляционные базы данных, в отличии от их предшественников, помогают проектировщикам, программистам и пользователям поддерживать однозначность данных, их полноту, и целостность. И как следствие - достоверность, что, впрочем, когда речь заходит о бухгалтерской программе, в немалой степени зависит от пользователя, т.е. бухгалтера :-)
Что ж, приступим, наконец, с Божей помощью.
Тем, у кого установлен Microsoft Office, нужно открыть программу MS Access: файл - создать - новая база данных - дать имя файлу "Rashod" и нажать кнопку "Создать".






Далее нужно нажать "Создание таблицы в режиме конструктора".
Ниже на примере показано, как в конструкторе создана таблица Main, какие она содержит поля, каких типов эти поля:




Обратите внимание, что поле ID содержит уникальную нумерацию, организовывается такое поле путем нажатия пиктограммы ключа. Обычно такое поле имеет тип целочисленный  "счетчик", т.е. автоматически увеличивает свое содержимое на 1 при добавлении новой записи. Уникальность значений в этом поле обуславливается свойством "Индексированное поле", в котором указано, что совпадения не допускаются.
Позже Вы установите для себя, что действительно в таком поле значения уникальны. Предположим, что Вам все же удалось удалить Петрова из таблицы 1, поле "ID" которой организовано как счетчик с уникальными значениями. Тогда после добавления новой записи, значение поля ID никогда уже не станет равным 2. Новая фамилия будет добавлена в строчку под номером 4, и значение ID=2 никогда уже не появится в таблице 1.
Для программы "Расходы" нужно создать базу данных из следующих таблиц:



Все таблицы в зависимости от их назначения можно разделить на четыре типа:
  1. Кодификаторы (или справочники) - это таблицы Accounts, Credits, ExpenseGroup, MOs, Val, которые представляют из себя зачастую простые списки по типу Таблицы 1, описанной выше. Они постоянно хранят ту информацию, для которой предназначены.
  2. Корреляционные (вспомогательные). Корреляционная таблица постоянно хранит взаимосвязь данных из других таблиц (как правило - справочников). К таким таблицам относится ExpenseAcc. Эта таблица не хранит никакой основной информации (а основной информацией в учете являются записи, отражающие хозяйственную деятельность, т.е. проводки), а лишь указывает к какой группе счетов относится тот или иной счет.
  3. Временные (вспомогательные).  Временные таблицы нужны для временного хранения результатов каких либо расчетов. Это таблица Oborot. Как Вы увидите ниже, я даже не включил эту таблицу в схему данных, так как временная таблица может не иметь реляций с другими таблицами. Она их и не имеет.
  4. Главные (основные) таблицы. Эти таблицы хранят постоянно всю необходимую информацию. Прообраз главной таблицы из примера, приведенного выше - это Таблица 2. А в базе данных "Rashod.mdb" такая таблица одна и называется она Main.
На рисунке ниже я показал структуру базы данных





Как видно, в структуре присутствуют и объединены связями все таблицы, кроме временной.
Мимоходом замечу, что так или почти так организуются базы данных в других средах разработки. Выбор средства хранения Вашей базы данных целиком зависит от решаемой задачи. Например, для решения данной задачи можно было бы использовать SQL-Server под хранилище Вашей базы данных. Но, тогда на тех компьютерах, где Вы соберетесь использовать Вашу будущую программу должен присутствовать и быть запущен этот сервер. Для такой задачи это неудобно.
На этом сегодня все. Если у кого-то остались вопросы, а я прекрасно понимаю, что в рамках такого короткого урока я только дал основные направления, прошу написать мне любым доступным способом.
Наглядный видео урок Вы можете посмотреть или скачать.

Что же дальше?
Любая программа должна начинаться с заставки, но лучше, если есть возможность эту заставку отключать.