Software Development Kit
to the Delphi-Win32 and Free Pascal compilers
Home > Wiki > OPF

OPF

english (en) | português (br)

PressObjects' object persistence framework (OPF) is, among the mayor frameworks, the one the requires the least from the user. All that the framework needs is already defined in the model, or more accurately in the business classes' Metadata.

However, to get the most out of this framework, some tips are necessary.

Contents

Creating the database

PressObjects'OPF does not send DDLs directly to the database, neither does it create a new database for the user, but it helps in creating a script that can be executed to create the tables, indexes, constraints and generators for the database.

To create this script:

uses
  PressOPF;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Text := PressOPFService.CreateDatabaseStatement;
end;

That's it. The method CreateDatabaseStatement creates a text block that can be executed by a database.

This routine can be optimized some more:

uses
  Clipbrd, PressOPF;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Clipboard.AsText := PressOPFService.CreateDatabaseStatement;
end;

To create the application's database, its enough to have this routine in a button or as a menuitem in the application. After execution, just paste it in the text box of the database's front-end.

Long Identifiers

All the objects created by the PressObjects' CreateDatabaseStatement use logical names, derived from the tables and fields names.

However, its common that some field name are longer than the maximum allowed by the database. When this happens, the CreateDatabaseStatement method gives an alert in the first lines of the script.

To reduce the size of the names of these objects, you have the choice of changing the names of the tables or define a short name, used only to name relational tables NxN and constraints.

Persistent name and short name

The persistent name and the table name or the attribute in the database, can be completely different from the name used in the application. To change the persistent name, include the option PersistentName inside the metadata class:

class function TProduct.InternalMetadataStr: string;
begin
  Result := 'TProduct IsPersistent PersistentName="Prod" (' +
   'Name: String(80);' +
   'Price: Currency;' +
   ')';
end;

The short name is an alternative in cases where the object's name is not long, but some of the names of the objects created by the framework, such as constraints or other tables, exceed the maximum allowed by the database.

This problems occurs more frequently in fields of type Parts and References, when these need to create an auxiliary table (NxN). For Example:

class function TBudgetItem.InternalMetadataStr: string;
begin
  Result := 'TBudgetItem IsPersistent (' +
   'Completions: References(TComplete) ShortName="Compl";' +
   ')';
end;

In the above example, the fieldname continues with the name "Completions", but the objects derived from it will use "Compl" to compose their respective names.

Object's Class

All objects saved in the database needs to save, the name of its class. This resource allows for searching of a certain class and object instances correctly. For example:

uses
  PressSession;

...

var
  VList: TPressProxyList;
begin
  VList := Session.OQLQuery('select * from any TContact');
  try

...

VList can hold objects of TPerson and TCompany classes, all descendants of TContact. Read more about OQL and other object retrieval methods in the article Retrieve objects.

Therefore the PressObjects' model defines a field "ClassId" automatically to store this information.

To use the resource and avoid having a string of 32 positions in every table and messing up the normalization, the PressModel has a property that allows the naming of a table with all the class names in the model. If this property is filled, the ClassId field gets an ID instead of the class name.

uses
  PressSubject;

...

initialization
  PressModel.ClassIdStorageName := 'ModelClass';

In the above example, a table with the name ModelClass will be created with to fields: an ID and a ClassName.

Numeric OID

By default, the OID of a PressObjects' model is a string of 32 positions, long enough for a GUID. GUID is the default OID, in case the application does not provide the name of a generator, nor registers a Generator Class for the OPF.

To make a numeric OID, use a database generator and ... its enough to define two properties in the PressModel.

uses
  PressSubject,
  PressAttributes;

initialization
  PressModel.DefaultGeneratorName := 'gen_app';
  PressModel.DefaultKeyType := TPressInteger;

That's it. If the metadata defined does not state anything else, the OPF will use gen_app as the name of the OID generator and Integer as the type.

Read more about Id generation.

Owner of the Parts Object

All Parts attributes references objects in another table. Due to the type of relationship, its not possible to list the objects without creating a third table, unless the Parts object known its owner. Let's see some examples:

An object of the class TTelephone can be part of more than one budget at the same time. In the same TTelephone table, a list of telephones of types TVendor, TClient or TBranch can be saved.

At the start, as TTelephone does not have a unique owner, the only way to relate telephone and client is by making an intermediate table. Do not worry about this, as PressObjects does all the work for this under the covers.

On the other hand, let's assume that all these classes have inherited from a common superclass: TContact. TContact has an attribute called Phones, of the type Parts(TTelephone). In this case, TTelephone has only one owner and this allows the elimination of the auxiliary table with the follow trick:

class function TTelephone.InternalMetadataStr: string;
begin
  Result := 'TTelephone IsPersistent OwnerClass=TContact (' +
   'Type: Reference(TTelephoneType);' +
   'Number: TNumberTelephone;' +
   ')';
end;

The property OwnerClass associates the owner with a class which its instances are owned by another object, and therefore eliminates the need for an auxiliary table.

The example above defines another PressObjects' resource: developer attribute (TNumberTelephone). Read more about this attribute in the article Creating Attributes.