A quick guide to tiOPF

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:

Lets you build an object oriented application that can swap databases with the flick of a command line parameter, conditional define or registry switch.
Currently we have the following persistence layers available:

Interbase/Firebird via IBX

Firebird via FBLib

Firebird via ZeosLib (experimental)

Oracle via DOA

MS Access & MS SQL-Server via ADO

Paradox via BDE

XML via MSDOM or FPC's DOM

CSV files

TAB files

There is also a lightning fast, custom XML persistence layer for local databases, and

a HTTP/XML layer & proxy server for building remote systems that can connect through corporate firewalls.

Support

What are the advantages?

tiOPF provides database independence.
You can change databases by changing the persistence layer.
This can be as simple as changing a couple of lines of code.

Your code can be more object orientated rather than record orientated.

What are the disadvantages?

A heavy learning curve.

tiOPF is more code orientated and less RAD than using databases and data aware controls.

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.

There are 6 steps:

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:

Override Save and Read and make them public (for automapping it is sufficient to call the inherited handler):

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

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

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.