Глава 2. Основные положения


Архитектура системы

ONTARIO1 представляет собой фреймворк (framework), ориентированный на применение в системах учета для быстрого построения бизнес-приложений. Фреймворк существует в виде библиотеки классов Delphi и реализации методов этих классов, касающихся доступа и обработки данных в виде процедур (stored procedures) сервера БД MS SQL Server. MS SQL Server имеет достаточно мощное расширение ANSI SQL-92 в виде языка Transact SQL, который позволяет реализовать сложную обработку данных на сервере БД.

Условно структуру системы можно разбить на три части или слоя:

Объектная логика реализована в виде библиотеки классов Delphi. Все классы в ONTARIO1 наследуются от единого базового класса. Каждый класс имеет также свои визуальные формы для отображения информации в клиентском приложении, которые также наследуются от соответствующих форм суперклассов.

В самой системе можно выделить две основных части:

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

Delphi представляет собой визуальную объектно–ориентированную среду разработки и программирования, в то время как MS SQL Server является реляционной СУБД. Объектный подход к логической организации данных на основе реляционной модели их хранения и обработки позволяет исключить прямой доступ к таблицам со стороны клиентского приложения, которое не знает, как именно и где расположены сами данные, но знает интерфейсные методы их получения, используя в качестве API механизмы вызова встроенных процедур сервера БД.

Объект в понятии приложения и БД является некоторой сущностью - отражением объекта реального мира, обладающей определенными свойствами (атрибутами) и методами (процедурами), вся информация о которой, связанная с логикой интерфейса пользователя содержится в самом приложении, тогда как логика обработки данных-в базе.

Объект создается на основе класса, который представляет собой специализированный класс (компонент) Delphi, обладающий базовыми свойствами, методами и обработчиками событий, связанных с данными в базе, и непосредственно интерпретирующий объектную модель обработки данных в реляционную путем вызова в интерфейсных методах класса процедур БД. Таким образом, свойства объекта явно хранятся в БД в виде атрибутов отношений либо неявно в виде результатов выполнения встроенных процедур. Методы можно разделить условно на управляющие данными, управляющие интерфейсом и смешанные. Методы управления данными в общем случае состоят из вызова одной или более встроенных процедур БД, например, метод для пересчета суммы двух атрибутов объекта и сохранения ее в третьем. Управляющие интерфейсом состоят из логики взаимодействия с пользователем в зависимости от класса объекта, например, заполнение опций контекстного меню объекта в приложении смысловым содержанием доступных методов. Смешанные методы обладают всеми перечисленными возможностями, например, вывод интерфейсной формы для редактирования свойств объекта предваряется получением таковых из БД.

Объект существует в представлении клиентского приложения и одновременно в БД, которая содержит его свойства (атрибуты) и реализации методов (процедуры БД). Объекты в БД хранятся в виде древовидной иерархической структуры неограниченного уровня вложения. Объекты условно разделяются на "Папки" и "Не папки". Папки могут содержать в себе другие объекты, в том числе и папки, образуя поддерево. Для навигации по БД в клиентском приложении существует аналог Windows-Проводника, позволяющий перемещаться по папкам и производить действия со всеми объектами.

Соглашения об именованиях

Все имена файлов Delphi и MS SQL рекомендуется сокращать до 8 символов.

Классы именуются следующим образом. Первая буква - всегда T (Type), далее DBO (DataBase Object) и затем с заглавной буквы смысловое название класса, например TDBOUser, TDBOFolder и т.д. Исключение составляет базовый класс, который носит название TDBObject. Имя класса не должно превышать 16 символов.

Встроенные процедуры имеют разделение на системные и прикладные, реализующие тот или иной интерфейсный метод класса, связанный с обработкой данных. Системные процедуры имеют название вида spXXX, где sp – признак общесистемной процедуры, XXX – смысловое содержание, например spCreateObj - процедура создания объекта в БД. Прикладные процедуры всегда связаны с конкретным классом, поэтому их название начинается с имени класса, далее идет символ подчеркивания “_” и смысловое название, которое может и не совпадать с названием соответствующего метода. Например TDBObject_Create – процедура создания объекта класса TDBObject, а TDBObject_Save – процедура сохранения отредактированных свойств объекта класса TDBObject, используемая в системе не только при редактировании.

Названия полей (атрибутов) таблиц БД, создаваемых прикладными модулями, должны соответствовать смысловому содержанию и даются на английском языке с некоторыми сокращениями (не рекомендуется давать названия более 10-15 символов для эргономичности), с применением как верхнего, так и нижнего регистра латиницы. Например, поле хранения номера паспорта может иметь вид PaspNum и т.п. Для полей–идентификаторов (первичных и вторичных ключей) требуется применение в названии аббревиатуры ID (идентификатор), например FirmID – идентификатор фирмы.

Диалоговые формы именуются следующим образом. Начало названия состоит из frmDBO, далее название объекта и название соответствующего метода, который вызывает форму, например frmDBOUserEdit - форма редактирования класса "Пользователь". Файл, содержащий модуль формы, имеет длину 8 символов, поэтому он именуется по следующему принципу: первые 3–4 символа – краткое название класса без приставки TDBO, далее 4–5 символов – краткое название соответствующего метода. Например, для формы frmDBOUserEdit файл будет называться UserEdit.pas , а для формы frmDBOSendObjSend.pas .

При именование компонентов в формах следует придерживаться “венгерской” записи, которая состоит из префикса, обозначающего тип объекта или переменной, и суффикса со смысловым значением. Например dbgSubTree – Database Grid отображающий некоторое поддерево, dsrcSubTree – источник данных для этого поддерева и т.п. Значения префиксов компонентов в ONTARIO1 не являются обязательными и однозначно определенными для всех компонентов, поэтому их применение зависит от программиста. Можно рекомендовать только придерживаться того стиля, который используется в исходных программных кодах системы.

Для краткости изложения, члены данных класса далее по тексту именуются свойствами, а члены-функции - методами. В литературе, как правило, методами называют виртуальные члены-функции. В классах ONTARIO1 практически все члены-функции являются виртуальными, поэтому мы можем сделать такое допущение при изложении.

Базовый класс

Все классы ONTARIO1 наследуются от некоторого базового класса, который называется в системе "Абстрактный объект" (TDBObject), поэтому все сказанное о данном классе относится и ко всем другим классам системы. Данный класс было бы неверно называть абстрактным, так как большинство его методов виртуальны и уже имеют реализацию. Напомним, что абстрактный класс содержит только абстрактные виртуальные методы. Базовый класс обладает следующими свойствами:

Табл.2.1. Свойства базового класса TDBObject

Наименование

Тип данных

Краткое описание

OID целое Уникальный идентификатор объекта
Name строка (128) Наименование объекта
Ext строка (128) Расширение наименования (дополнительная информация об объекте)
CreationDate дата и время Дата и время (как правило - создания объекта)
Attrib целое Атрибут для хранения информации в подклассах
Summ денежный Атрибут для хранения информации в подклассах
State строка (16) Атрибут для хранения информации в подклассах
FolderID целое ID папки, в которой расположен данный объект, если 0 - в корне
Deleted целое признак того, что объект логически удален
OwnerID целое ID создателя объекта
Shortcut целое Признак, является ли объект ссылкой (1) или нет (0)
OriginID целое ID объекта, ссылкой на который является данный объект
BaseClass строка (16) Имя класса объекта
DelMode целое Режим удаления объекта (0-логический, 1-физический, 2-запрещен)

Свойства объектов базового класса, хранятся в БД в таблице Objs, содержащей все вышеперечисленные свойства абстрактного класса в виде одноименных атрибутов (полей). Каждый объект имеет уникальный идентификатор (номер), который одновременно является его первичным ключом. OID может принимать значения от 1 до 231-1. Иерархическое хранение объектов достигается за счет наличия ссылки FolderID, при этом ссылка на FolderID=0 является признаком того, что объект находится в корневой папке. Корневая папка имеет OID=0, не существует в БД и является виртуальной папкой.

Базовый класс имеет следующие методы:

Табл.2.2. Методы базового класса TDBObject

Название Форма Delphi Краткое описание
CreateDBO TfrmDBOCreate Вызывает форму создания нового объекта
CreateDBOClone - Инициирует в системе создание нового объекта по некоторому уже существующему
DeleteDBO TfrmDBODelete Вызывает форму удаления объекта из системы
UndeleteDBO TfrmDBOUndelete Вызывает форму восстановления логически удаленного объекта
Edit TfrmDBOEdit Вызывает форму редактирования объекта
View TfrmDBOView Вызывает форму просмотра объекта
Move TfrmDBOMove Вызывает форму перемещения объекта из папки в папку
Print - Вызывает форму печати объекта, если таковая существует
PrintToWord TfrmDBObjectExportForms Экспортирует свойства объекта в форму документа MS Word и переходит в режим печати, если таковая существует
ExportFormToWord TfrmDBObjectExportForms Экспортирует свойства объекта в форму документа MS Word, если таковая существует
SendToUser TfrmDBOSendToUser Вызывает форму пересылки объекта пользователю
MakeShortcut TfrmDBOMakeShortcut Вызывает форму пересылки ссылки на объект пользователя
SetPermissions TfrmDBOAccess Вызывает форму просмотра и изменения прав доступа к объекту
SysInfo TfrmDBOSysInfo Вызывает форму просмотра системных свойств объекта
ViewPath TfrmDBOViewPath Вызывает форму просмотра пути к объекту в дереве папок
ViewHistory TfrmDBOViewHistory Вызывает форму просмотра истории изменений объекта

Базовые формы

Как следует из описания методов, логика реализована в формах базового класса и процедурах БД, которые вызываются этими формами. Иерархия базовых классов форм в ONTARIO1 имеет следующую структуру:

TForm
\------ TfrmBaseDialog
\--------------- TfrmBaseView
\ \--------------------------- TfrmDBOView
\ \--------------------------- TfrmDBOSysInfo
\ \--------------------------- TfrmDBOViewPath
\ \--------------------------- TfrmDBOViewHistory
\--------------- TfrmBaseEdit
\ \--------------------------- TfrmDBOCreate
\ \--------------------------- TfrmDBOEdit
\ \--------------------------- TfrmDBOAccess
\--------------- TfrmBaseAction
\ \--------------------------- TfrmDBODelete
\ \--------------------------- TfrmDBOUndelete
\ \--------------------------- TfrmDBOMove
\ \--------------------------- TfrmDBOSendToUser
\ \--------------------------- TfrmDBOMakeShortcut
TfrmModalDlg
\--------------- TfrmDBObjectExportForms

Рис.2.1. Иерархия базовых классов форм

Интерфейс формы TfrmBaseDialog описана в файле BaseDlg.pas как:

TfrmBaseDialog = class( TForm )
. . .
public
    DataChanged: boolean;
    DBOInfo : TDBOInfo;
    hSender : HWND;
    RetCode : integer;
    procedure FormPrint; virtual;
    procedure FormRefresh; virtual;
    procedure InitDataEnvironment( DBOInfo: TDBOInfo ); virtual;
    procedure InitFromTemplate( TemplateID: integer ); virtual;
    procedure InitClone( MasterOID: integer ); virtual;
    procedure InitFormControls; virtual;
    function ValidCheck: boolean; virtual;
    procedure BeginTransaction; dynamic;
    procedure Commit; dynamic;
    procedure Rollback; dynamic;
published
    property ContextHelp : boolean read GetContextHelp write SetContextHelp;
    property OnRefreshData: TNotifyEvent read FOnRefreshData write FOnRefreshData;
end;

Остановимся подробнее на назначении методов базовых классов форм.

Виртуальный метод InitDataEnvironment является стандартным для инициализации компонентов доступа к данным в форме, например для инициализации параметров вызова встроенных процедур чтения данных из БД. Он должен вызываться сразу после создании формы в программе, как это сделано, например в методе View класса DBObject:

procedure TDBObject.View;
    var frmView: TfrmBaseDialog;
begin
    if MethodFormRef = nil then MethodFormRef := TfrmDBOView;
    frmView := MethodFormRef.Create( Application );
    frmView.InitDataEnvironment( DBOInfo );
    frmView.InitFormControls;
end;

Здесь DBOInfo - структура типа TDBOInfo, содержащая свойства базового класса, приведенные в табл.2.1. Само описание структуры приведено в DBOConst.pas.

Виртуальный метод InitFormControls выполняет восстановление размеров окна формы и некоторых ее компонентов, например, ширину колонок в DBGrid. Состояние формы автоматически запоминается в файле конфигурации ontario.ini при закрытии формы, унаследованной от TfrmBaseDialog.

Виртуальная функция ValidCheck предназначена для проверки корректности заполнения тех или иных полей в форме либо каких–либо других логических условий. Она автоматически вызывается всякий раз при попытке сохранить отредактированные данные в форме и при успешной проверке далее вызывается виртуальный метод SaveDataEnvironment. Программисту требуется лишь при необходимости проверок переопределить функцию следующим стандартным образом, например так:

function TfrmDBOAccCalcEdit.ValidCheck: boolean;
begin

    Result := inherited ValidCheck;
    { код проверки корректности заполнения формы }

    if edtBank.Value = 0 then
    raise Exeption.Create( 'Не заполнено поле <Банк>' );
end;

В свойстве RetCode помещается результат последней выполненной встроенной процедуры записи данных в БД, которых в форме с увеличением наследуемых классов будет прибавляться. Для этого следует явно после выполнения очередной процедуры присваивать свойству RetCode параметр Result, но это происходит в виртуальном методе SaveDataEnvironment – стандартном методе записи изменений при редактировании, создании и других операциях. Данный метод появляется только в классе форм TfrmBaseEdit, являющимся базовым для всех форм любого вида редактирования объектов БД. Если в процессе существования формы данные были изменены (соответственно, DataChanged = true), то всегда вызывается диалог, позволяющий выбрать отказ или сохранение изменений. В случае выбора сохранения изменений следует вызов метода SaveDataEnvironment.

TfrmBaseEdit = class( TfrmBaseDialog )
. . .
public
    procedure SaveDataEnvironment; virtual;
end;

Все действия, исполняемые в процедуре SaveDataEnvironment выполняются в транзакции, причем это является свойством уровня ядра и не требует никакого программирования со стороны прикладного разработчика.

Стандартное использование транзакций, обеспечивающее целостность данных и обработку ошибок, возвращаемых сервером – в переопределяемом методе SaveDataEnvironment или в обработчике события нажатия кнопки “ОК” – реализуется автоматически в любой форме, унаследованной от TfrmBaseEdit и TfrmBaseAction или методе абстрактного объекта. Программисту нет необходимости думать о транзакциях при использовании стандартных средств. Рассмотрим типичный пример в форме создания нового объекта класса “Пользователь”:

procedure TfrmDBOUserCreate.SaveDataEnvironment;
begin
   inherited;
   spTDBOUser_Create.Active := false;
    spTDBOUser_Create.ParamByName( '@OID' ).AsInteger := DBOInfo.OID;
    spTDBOUser_Create.ParamByName( '@Login' ).AsString := edtLogin.EditText;
    spTDBOUser_Create.ExecProc;
    RetCode := spTDBOUser_Create.ParamByName( 'Result' ).AsInteger;
end;

Если все же возникнет необходимо управлять транзакциями, используйте API абстрактного объекта (TDBObject) либо одноименные методы диалоговой формы (TfrmBaseDialog):

procedure BeginTransaction – начинает транзакцию;
procedure Commit – фиксирует транзакцию;
procedure Rollback – откатывает транзакцию.

Класс форм TfrmBaseAction является базовым для всех форм, где присутствует диалог типа “ОК – Отменить”, например в диалоге пересылки объекта (форма TfrmDBOSend). Методы InitDataEnvironment, ValidCheck здесь также присутствуют, причем SaveDataEnvironment автоматически вызывается обработчиком события нажатия кнопки “ОК”.

 


Содержание Глоссарий Предыдущая Следующая