tiOPF
Free, Open Source Object Persistence Framework for
Free Pascal & Delphi

A quick guide to tiOPF

provided by Sean Cross of Source IT Software

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

What is tiOPF

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.

Key Features

From the website:
Some of the key features of the tiOPF include:

Support

What are the advantages?

What are the disadvantages?

 

How do I create a business object?

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.

 

How do I persist it?

Examples from MastApp, using an access database.

There are 6 steps:

  1. Include your persistence layer units and OID units:
  2. Set your default persistence layer:
  3. Connect to the database:
  4. Set your persistence mapping:

    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:

  5. Override Save and Read and make them public (for automapping it is sufficient to call the inherited handler):
  6. Read/Save your object lists:

 

How do I create a database?

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

 

How do I filter it.

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

 

How do I build a GUI?

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.

 

How do I use data aware controls?

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.

 

Useful units and functions.

Unit

Contains

tiObjectTtiObject and TtiObjectList
tiFilteredObjectListTtiFilteredObjectList
tiCriteriathe TPerCriteria objects used in TtiFilteredObjectList
tiOPFManagergTIOPFManager
tiAutoMapAutomapping
tiVisitorDBAutoGenTVisDBAutoGenRead and Update used in DB Independent Visitors
tiVisitorDBTVisOwnedQrySelect and Update used in Hard Coded Visitors
tiOIDbase OID. Needs to be included in your business model unit.
tiOIDGUIDGUID OID. Needs to be included in your project at least once if you require guid OIDs
tiOIDIntegerInteger OID. Needs to be included in your project at least once if you require int OIDs
tiQueryContains 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

tiQueryXMLLINK_XML
tiQueryIBXLINK_IBX
tiQueryBDEParadoxLINK_BDEPARADOX
tiQueryADOAccessLINK_ADOACCESS
tiQueryADOSQLServerLINK_ADOSQLSERVER
tiQueryCSVLINK_CSV
tiQueryTABLINK_TAB
tiQueryXMLLightLINK_XMLLIGHT
tiQueryDOALINK_DOA
tiQueryRemoteLINK_REMOTE
tiQuerySqldbIBLINK_SQLDB_IB
tiQuerySqldbPQLINK_SQLDB_PQ
tiQueryFBLLINK_FBL
tiQueryZeosIBFBLINK_ZEOS_FB

 

ADVANCED TOPICS

How do I encapsulate and associate objects?

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:

 

Visitors

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).

Important features of TtiVisitor are:

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.

 

Persistence mapping

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.

 

Automapping:
Automapping is the simplest persistence mapping. Simply call;
gTIOPFManager.ClassDBMappingMgr.RegisterMapping for each field to be persisted,
and call
gTIOPFManager.ClassDBMappingMgr.RegisterCollection for each collection object.
this is done once, at start up.

Example from Demo_Collection

 

DB Independent Visitors:
DB Independent Visitors (DBIV) require creating 4 visitors for each class to be persisted; read, create, update and delete visitor objects. These objects need to be registered at start up. This provides more control than automapping at the cost of considerably more code.

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).

The advantage over automapping is that you have more control over the makeup of the sql.
 
Hard Coded Visitors
Hard Coded Visitors also require the creation and registration of 4 visitors. However, they simply provide an empty Query object, and creation of the sql is left to the developer.

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.

 

Which persistence mapping should I use?

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.