tiOPF |
Free, Open Source Object Persistence Framework for Free Pascal & Delphi |
This guide is designed to be read in conjunction with the tiOPF 2 and the associated demos.
tiOPF can be downloaded from the tiOPF Web Site
tiOPF is a Object Persistence Framework. That is, it is a framework based around saving your objects to, and loading them from, databases and/or flat files.
According to the website:
tiOPF is an Open Source framework for Delphi & Free Pascal that simplifies the mapping of an object oriented business model into a relational database. The framework is mature and robust having been in use on production sites since 1999. It is free, open source, and available for immediate download with full source code.
From the website:
Some of the key features of the tiOPF include:
Business objects descend from TtiObject.
All TtiObject descendants have a unique Object ID with a property name of OID. This is of type integer, 64 bit integer or GUID. The OID is populated when a new object is created. The OID is saved and loaded automatically.
Other fields needing persistence are declared as published.
Object initialisation is done in CreateNew.
Example - taken from Demo_Collection:
Business objects are normally stored in a TtiObjectList descendant.
This can be as simple a declaration as:
Commonly however Add and Items are reintroduced to provide type safety
Example - taken from MastApp:
New items are created with CreateNew
Example - taken from Demo_Collection:
Items are deleted by setting the Deleted property to True.
Note that they are only removed when the object list is persisted.
Examples from MastApp, using an access database.
This depends on what mapping you are using, Automapping, DB Independent or hard coded. This is covered in a later section. Automapping is the simplest.
An object is mapped as follows:
You can create a dataset as you would normally, and then map your objects to it.
However you can also create a database in code using the persistence layer.
Example - from Demo_CreateDatabase:
Tables are created using TtiDBMetaDataTable.
Example - from Demo_CreateTable
The easiest way to filter an object list is by descending from TtiFilteredObjectList.
Example from Demo_CollectionWithCriteria
An object list can also be filtered using Hard Coded Visitors.
See Demo_CollectionWithFilter
One of the main Gui elements is TtiVTListView. Columns are added using AddColumn, passing in the property name, type, display name and display size. To populate, the Data property is set to a TtiObjectList.
Example from Demo_EditDataInGui
Add, Edit and Delete capabilites are provided using the OnEdit, OnInsert and OnDelete events.
tiOPF also comes with a number of object aware controls such as TtiPerAwareEdit. These use the LinkToData method to attach to a TtiObject
A GUI can also be built using standard non-db components and mediating views. Base edit and list mediator controls are provided in the GUI directory.
There is a demo in \tiOPF2_Demos\GenericMediatingViews.
Use TTiDataset and TtiNestedDataset. These are included in the latest svn. They may not yet be available in the download version
TtiDataset is linked to an object list using the method LinkObject defined as follows:
TtiNestedDataset is linked to an existing TtiDataset or TtiNestedDataset using the properties DataSetField and ObjectClass as follows:
See the dataset demo and unit tests for further information.
Unit |
Contains |
tiObject | TtiObject and TtiObjectList |
tiFilteredObjectList | TtiFilteredObjectList |
tiCriteria | the TPerCriteria objects used in TtiFilteredObjectList |
tiOPFManager | gTIOPFManager |
tiAutoMap | Automapping |
tiVisitorDBAutoGen | TVisDBAutoGenRead and Update used in DB Independent Visitors |
tiVisitorDB | TVisOwnedQrySelect and Update used in Hard Coded Visitors |
tiOID | base OID. Needs to be included in your business model unit. |
tiOIDGUID | GUID OID. Needs to be included in your project at least once if you require guid OIDs |
tiOIDInteger | Integer OID. Needs to be included in your project at least once if you require int OIDs |
tiQuery | Contains the base TtiQuery object |
Standard Persistence layers Either include the required unit, or use the LINK_XXX conditional define.
See Demo_LoadPersistenceLayerIfDef or Demo_LoadPersistenceLayerUses.
Persistence |
Conditional |
tiQueryXML | LINK_XML |
tiQueryIBX | LINK_IBX |
tiQueryBDEParadox | LINK_BDEPARADOX |
tiQueryADOAccess | LINK_ADOACCESS |
tiQueryADOSQLServer | LINK_ADOSQLSERVER |
tiQueryCSV | LINK_CSV |
tiQueryTAB | LINK_TAB |
tiQueryXMLLight | LINK_XMLLIGHT |
tiQueryDOA | LINK_DOA |
tiQueryRemote | LINK_REMOTE |
tiQuerySqldbIB | LINK_SQLDB_IB |
tiQuerySqldbPQ | LINK_SQLDB_PQ |
tiQueryFBL | LINK_FBL |
tiQueryZeosIBFB | LINK_ZEOS_FB |
Encapsulation is normally done by including an object or object list inside another.
A one to many relationship can be modelled by including a TtiObjectList containing the children, inside the parent. Alternately, the child can contain an instance of the parent.
A third possibility is to store just the OID of the associated object. This is useful when access to the object itself is not required.
If the encapsulated object is published, then it will be saved and loaded together with it's owner. If it is public, then the saving and loading will need to be handled in code.
Examples from MastApp:
tiOPF uses the Visitor pattern extensively. Reading and Saving objects is done using visitors. An in depth knowledge of visitors is not required to use tiOPF successfully.
An executive summary is as follows:
Visitor objects iterate over a collection of objects and perform an operation on each acceptable object. In tiOPF terms, visitors descend from TtiVisitor and operate on descendants of TtiObject (this includes TtiObjectList).
Visited Property - the object currently being operated on.
AcceptVisitor virtual method - used to determine if the Visited object should be operated on.
Execute virtual method - that actually performs the operation on Visited.
For more information, see chapter 2 of the concepts manual.
As mentioned, there are 3 types of persistence mapping, AutoMapping, DB Independent Visitors and Hard Coded Visitors. Automapping will work with both flat files (xml, csv etc) and databases. DB Independent and hard Coded will only work with databases.
Most demos allow you to choose the mapping on start up so you can compare them.
Example from Demo_Collection
See Demo_Collection, Client_DBIndependentVisitors_Svr.pas for implementation details.
Under the hood, the visitors create a sql statement based on the parameters supplied (table name and field names).
HCV should be used when you need precise control of the sql, or when you sql doesn't fall into the "Select * from ..." Table mould.
For flat files (xml etc), use automapping.
Both Automapping and DBIV use "Select * from ..." queries, so if this is not suitable (bringing back too many unwanted fields) then use HCV.
Otherwise the difference in coding required is such that you are best off starting with automapping and then replacing it as required.
Note: it is possible to mix and match. E.g. use a HCV to select the data and then use Automapping to perform the updates.
Feature required |
Automapping |
DB Independent |
Hard Coded |
Flat files | Yes | No | No |
Use stored procedures | No | No | Yes |
Swap databases easily | Yes | Yes | Maybe |
Control over sql | No | Limited | Complete |
Performance | None | Limited | Complete |
More to come ... please stay tuned.