📄 tiofp documentation - a worked example of using the tiopf.htm
字号:
<P>State</P></TD>
<TD vAlign=top width=104>
<P>state </P></TD>
<TD vAlign=top width=132>
<P> </P></TD></TR>
<TR class=Normal>
<TD vAlign=top width=83>
<P> </P></TD>
<TD vAlign=top width=95>
<P> </P></TD>
<TD vAlign=top width=94>
<P>PCode</P></TD>
<TD vAlign=top width=104>
<P>pcode </P></TD>
<TD vAlign=top width=132>
<P> </P></TD></TR>
<TR class=Normal>
<TD vAlign=top width=83>
<P> </P></TD>
<TD vAlign=top width=95>
<P> </P></TD>
<TD vAlign=top width=94>
<P>Country</P></TD>
<TD vAlign=top width=104>
<P>country </P></TD>
<TD vAlign=top width=132>
<P> </P></TD></TR>
<TR class=Normal>
<TD vAlign=top width=83>
<P>TEAdrs</P></TD>
<TD vAlign=top width=95>
<P>EAdrs</P></TD>
<TD vAlign=top width=94>
<P>OID</P></TD>
<TD vAlign=top width=104>
<P>oid</P></TD>
<TD vAlign=top width=132>
<P>Primary key </P></TD></TR>
<TR class=Normal>
<TD vAlign=top width=83>
<P> </P></TD>
<TD vAlign=top width=95>
<P> </P></TD>
<TD vAlign=top width=94>
<P>Owner.OID</P></TD>
<TD vAlign=top width=104>
<P>owner_oid </P></TD>
<TD vAlign=top width=132>
<P>Foreign key to Person </P></TD></TR>
<TR class=Normal>
<TD vAlign=top width=83>
<P> </P></TD>
<TD vAlign=top width=95>
<P> </P></TD>
<TD vAlign=top width=94>
<P>EAdrsType</P></TD>
<TD vAlign=top width=104>
<P>eadrs_type </P></TD>
<TD vAlign=top width=132>
<P> </P></TD></TR>
<TR class=Normal>
<TD vAlign=top width=83>
<P> </P></TD>
<TD vAlign=top width=95>
<P> </P></TD>
<TD vAlign=top width=94>
<P>Text</P></TD>
<TD vAlign=top width=104>
<P>text </P></TD>
<TD vAlign=top width=132>
<P> </P></TD></TR></TBODY></TABLE>
<H2>A note about OIDs</H2>
<P>The framework supports several methods of Object Identifier (OID) generation.
Earlier versions of the framework used integers (which is what we will be using
here), but there is additional support for HEX and GUID OIDs. If none of these
are suitable, you can easily write your own by descending a new TOID descendent
class defined in TiPerObjOIDAbs.Pas. Remember to make your OID table in your
database match the storage requirements of OID. You must remember to Use the
appropriate OID class generation unit in your BOM otherwise you will get a
runtime error message “Attempt to create unregistered OID class”. Likewise, you
must also remember to include one and only one OID class generation unit.</P>
<H2>Application construction</H2>
<P>If you have not installed the tiOPF components, and setup the search path to
give access to the tiOPF files, then do this now following the instructions
under ‘Installing the tiOPF’</P>
<H2>Create a new application</H2>
<P>Create a directory to place the application source, and then create a Delphi
project group called ContactMgr_PG and save it.</P>
<P>Add the Delphi packages tiPersist.dpk and tiPersistIBX.dpk (because we are
starting by building an Interbase application with IBX) found in the
\TechInsite\tiPersist directory.</P>
<P>Add a new Delphi project. Call the main form FormMain, and save its pas file
as FMain.pas. Call the application ContactMgr.dpr</P>
<P>Arrange the projects in the project tree in the order of tiPersistCore,
tiPersistIBX then ContactMgr. This is important because of the dependencies
between the three projects. At the end of this, you will probably have a project
tree that looks something like this:</P>
<P><IMG height=165
src="tiOFP Documentation - A worked example of using the tiOPF_files/6_AWorkedExampleOfUsingTheTIOPF_clip_image001_0001.gif"
width=332> </P>
<P>I find the project tree provides a very hand way of navigating aroudn the
framework files. If I can’t remember a unit or class name, I can double click on
tiPersistCore and navigate all the units and classes in the package editor that
pops up.<BR>I like to have control over the directory that Delphi puts its
output files, so go to Project Options and select the Directories/Conditionals
tab. Check that the Directories/Conditionals settings of tiPersistCore and
tiPersistIBX looks like this:</P>
<P><IMG height=399
src="tiOFP Documentation - A worked example of using the tiOPF_files/6_AWorkedExampleOfUsingTheTIOPF_clip_image001_0002.gif"
width=424> </P>
<P>Note that we want to set the ‘Output directory’, ‘Unit output directory’ and
‘DCP output directory’. The location of the binaries and DCP files are the most
important because we will have to reference these files in the application and
will want to know where to look.</P>
<P>Set the ‘Output directory’ of the ContactMgr application to
C:\TechInsite\Bin. It is important that this is the same directory the package
BPL files will be placed in because the ContactMgr application will look for the
persistence layer it is to load in the same directory as its executable.</P>
<P>Select Project | Build all projects (I set-up a speed button for this because
I build all projects quite a bit), then run the ContactMgr and check the files
have been output to the directories we expect.</P>
<P>Note, we really want to know where the BPL files are being placed. Delphi
will put them in the \Delphi\Bin directory by default. If you have two copies of
the same BPL on the search path, and Delphi is not loading the copy you think it
is, it can cost you hours of unnecessary debugging (this one still catches me
out sometimes).</P>
<H2>Code the business object model</H2>
<H2>Setting up the pas files</H2>
<P>Add a new unit to the project and save it under the name ContactMgr_BOM.pas.
The root of the name is not important, but the _BOM bit is. We will be creating
a family of three units with the names *_BOM,.pas, *_Cli.pas and *_Srv.pas to
hold the business object model, server side visitors and client side single
instance of the BOM</P>
<P>We have seven classes to create (TContactMgr, TPeople, TPerson, TAdrsList,
TEAdrsList, TAdrs, and TEAdrs) and will create them one at the time, then
populate them with some hard coded data. We will use tiShowPerObjAbs to look
inside the objects as we are building them to confirm the structure is working
as expected.</P>
<P>Load ContactMgr_BOM.pas in the editor and add tiPtnVisPerObj to the uses
clause. Add the class declaration for TContactMgr like this:<BR></P><PRE>unit ContactMgr_BOM;
interface
uses
tiPtnVisPerObj,
tiPerObjOIDAbs,
tiPerObjOIDInteger,
;
type
TContactMgr = class( TPerObjAbs )
implementation
end.</PRE>
<H2>Setting up some code templates</H2>
<P>Ctrl+Left Click TPerObjAbs and you will be taken to its declaration. Directly
above the declaration of TPerObjAbs, there are two stubs of code (in comments)
which you can paste into ContactMgr_BOM to help get started when writing the
interface of TPerObjAbs and TPerObjList descendants.</P>
<P>I usually make two entries in Delphi's Code Insight to speed the process of
creating TPerObjAbs and TPerObjList descendants. I add the following blocks of
code:</P>
<P>TPerObjList code stub. Code Insight Shortcut name: pol</P><PRE>TMyClasses = class( TPerObjList )
private
protected
function GetItems(i: integer): TMyClass ; reintroduce ;
procedure SetItems(i: integer; const Value: TMyClass); reintroduce ;
function GetOwner: TMyClasses; reintroduce ;
procedure SetOwner(const Value: TMyClasses); reintroduce ;
public
property Items[i:integer] : TMyClass read GetItems write SetItems ;
procedure Add( pObject:TMyClass; pbDefaultDispOrder:boolean = true ); reintroduce;
property Owner : TMyClass read GetOwner write SetOwner ;
published
end ;</PRE>
<P>TPerObjAbs code stub. Code Insight Shortcut name: poa</P><PRE>TMyClass = class( TPerObjAbs )
private
protected
function GetOwner: TMyClasses; reintroduce ;
procedure SetOwner(const Value: TMyClasses ); reintroduce ;
public
property Owner : TMyClasses read GetOwner write SetOwner ;
end ;</PRE>
<H2>Coding TContactMgr, TPeople and TPerson classes</H2>
<P>We will code these three classes together, and then populate the object model
with some data that is hard coded to test the framework.</P>
<P>Paste in code templates for TContactMgr (based on TPerObjAbs), TPeople (based
on TPerObjList) and TPerson (based on TPerObjAbs). Write forward declarations of
the three classes, and then add an owned instance of TPeople to TContactMgr so
the interface looks like this:</P><PRE>TContactMgr = class ;
TPeople = class ;
TPerson = class ;
TContactMgr = class( TPerObjAbs )
private
FPeople: TPeople;
protected
function GetCaption : string ; override ;
published
property People : TPeople read FPeople ;
public
constructor create ; override ;
destructor destroy ; override ;
end ;</PRE>
<P>The constructor and destructor manage the creation and destruction of the
owned instance of TPeople. Note that the property, People, is published so the
automatic iteration code that we developed in the TVisited class will detect the
owned class and pass the visitor over each node. We have also added the
overridden function GetCaption where simply return the string ‘Contact manager’
in the implementation. This will become useful when we start building the GUI
using the TtiTreeView.</P>
<P>Paste in a code stub for TPeople by copying the TPerObjList template. Change
the type of its Owner, and Items properties and modify the signature of their
get and set methods. So Owner is of type TContactMgr and Items is of type
TPerson. When you have finished, the interface of TPeople should look like
this:</P><PRE>TPeople = class( TPerObjList )
private
protected
function GetItems(i: integer): TPerson ; reintroduce ;
procedure SetItems(i: integer; const Value: TPerson); reintroduce ;
function GetOwner: TContactMgr; reintroduce ;
procedure SetOwner(const Value: TContactMgr); reintroduce ;
public
property Items[i:integer] : TPerson read GetItems write SetItems ;
procedure Add( pObject : TPerson ; pDefDispOrdr : boolean = true ) ; reintroduce ;
property Owner : TContactMgr read GetOwner write SetOwner ;
published
end ;</PRE>
<P>Hit Ctrl+Shift+C and Delphi will fill out the implementation of TPeople. You
how have to hand craft the code for GetItems, SetItem, GetOwner, SetOwner and
Add. This takes no time at all because I have Code Insight templates set-up for
each of these called igi (inherited GetItems), isi (inherited SetItems), igo,
iso and ia.</P>
<P>The finished implementation of TPeople looks like this:</P><PRE>// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// *
// * TPeople
// *
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
procedure TPeople.Add(pObject: TPerson; pDefDispOrdr: boolean);
begin
inherited Add( pObject, pDefDispOrdr ) ;
end;
function TPeople.GetItems(i: integer): TPerson;
begin
result := TPerson( inherited GetItems( i )) ;
end;
function TPeople.GetOwner: TContactMgr;
begin
result := TContactMgr( inherited GetOwner );
end;
procedure TPeople.SetItems(i: integer; const Value: TPerson);
begin
inherited SetItems( i, Value ) ;
end;
procedure TPeople.SetOwner(const Value: TContactMgr);
begin
inherited SetOwner( Value ) ;
end;</PRE>
<P>And the finished implementation of TPerson looks like this:</P><PRE>// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// *
// * TPerson
// *
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
function TPerson.GetOwner: TPeople;
begin
result := TPeople( inherited GetOwner );
end;
procedure TPerson.SetOwner(const Value: TPeople);
begin
inherited SetOwner( Value ) ;
end;</PRE>
<P>This takes very little time to had code with the help of Code Insight,
however it would be still quicker with the help of a wizard, or a UML tool to
output the Delphi code. We will add this functionality to the tiOPF one day in
the future.)</P>
<P>Next, add the properties LastName, FirstName, Title, Initials and notes to
TPerson. Hit Ctrl+Shift+C and Delphi will finish off the interface declaration.
The interface of TPerson now looks like this:</P><PRE>//----------------------------------------------------------------------------
TPerson = class( TPerObjAbs )
private
FTitle: string;
FFirstName: string;
FInitials: string;
FLastName: string;
FNotes: string;
protected
function GetOwner: TPeople; reintroduce ;
procedure SetOwner(const Value: TPeople ); reintroduce ;
public
property Owner : TPeople read GetOwner write SetOwner ;
published
property LastName : string read FLastName write FLastName ;
property FirstName : string read FFirstName write FFirstName ;
property Title : string read FTitle write FTitle ;
property Initials : string read FInitials write FInitials ;
property Notes : string read FNotes write FNotes ;
end ;</PRE>
<H2>Testing TContactMgr, TPeople and TPerson classes</H2>
<P>We shall now create a single instance of TContactMgr, populate it with some
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -