Skip to content

InstantPersistence

Unit: InstantPersistenceCategory: Core

Overview

The InstantPersistence unit is the heart of InstantObjects, containing the fundamental classes for object persistence, attributes, and connector management. This unit provides:

  • TInstantObject - Base class for all persistent business objects
  • Attribute classes for all data types
  • TInstantConnector - Database connection management
  • TInstantObjectStore - Object caching and lifecycle management

Key Classes

TInstantObject

Base class for all persistent business objects in InstantObjects.

Inheritance: TInstantStreamableTInstantObject

Key Properties:

PropertyTypeDescription
IdstringUnique identifier for the object
PersistentIdstringOriginal ID when object was retrieved
UpdateCountIntegerOptimistic locking counter
IsChangedBooleanTrue if object has unsaved changes
IsPersistentBooleanTrue if object exists in storage
IsOwnedBooleanTrue if object is owned by another
ConnectorTInstantConnectorDatabase connector for this object

Key Methods:

pascal
// Lifecycle
constructor Create(AConnector: TInstantConnector = nil);
procedure Store;
procedure Refresh;
procedure Dispose;

// Retrieval
class function Retrieve(const AObjectId: string;
  CreateIfMissing: Boolean = False;
  ARefresh: Boolean = False;
  AConnector: TComponent = nil): TInstantObject;

// State Management
procedure SaveState;
procedure RestoreState;
function Clone(AConnector: TInstantConnector = nil): TInstantObject;

// Attributes
function AttributeByName(const AName: string): TInstantAttribute;
function FindAttribute(const APath: string): TInstantAttribute;

Events:

pascal
OnAfterCreate: TNotifyEvent;
OnAfterRetrieve: TNotifyEvent;
OnBeforeStore: TNotifyEvent;
OnAfterStore: TNotifyEvent;
OnBeforeDispose: TNotifyEvent;
OnAfterDispose: TNotifyEvent;
OnAttributeChanged: TInstantAttributeChangeEvent;
OnIdChanged: TInstantIdChangeEvent;

Example Usage:

pascal
var
  Contact: TContact;
begin
  // Create new object
  Contact := TContact.Create;
  try
    Contact.Name := 'John Doe';
    Contact.Email := 'john@example.com';
    Contact.Store;  // Save to database
    ShowMessage('Created with ID: ' + Contact.Id);
  finally
    Contact.Free;
  end;

  // Retrieve existing object
  Contact := TContact.Retrieve('CONT001');
  try
    Contact.Name := 'Jane Doe';
    Contact.Store;  // Update
  finally
    Contact.Free;
  end;
end;

TInstantAttribute

Base class for all attribute types.

Key Properties:

PropertyTypeDescription
NamestringAttribute name
OwnerTInstantObjectOwning object
IsChangedBooleanTrue if value changed
IsRequiredBooleanTrue if value required
IsDefaultBooleanTrue if default value
MetadataTInstantAttributeMetadataAttribute metadata

Simple Attribute Classes

TInstantString

Stores string values.

pascal
TContact = class(TInstantObject)
  _Name: TInstantString;
published
  property Name: string read GetName write SetName;
end;

function TContact.GetName: string;
begin
  Result := _Name.Value;
end;

procedure TContact.SetName(const Value: string);
begin
  _Name.Value := Value;
end;

Properties:

  • Value: string - The string value
  • Size: Integer - Maximum length from metadata

TInstantInteger

Stores integer values.

pascal
_Age: TInstantInteger;

property Age: Integer read GetAge write SetAge;

Properties:

  • Value: Integer - The integer value

TInstantFloat

Stores floating-point values.

pascal
_Price: TInstantFloat;

property Price: Double read GetPrice write SetPrice;

Properties:

  • Value: Double - The float value

TInstantCurrency

Stores currency values with precision.

pascal
_Salary: TInstantCurrency;

property Salary: Currency read GetSalary write SetSalary;

Properties:

  • Value: Currency - The currency value

TInstantBoolean

Stores boolean values.

pascal
_Active: TInstantBoolean;

property Active: Boolean read GetActive write SetActive;

Properties:

  • Value: Boolean - The boolean value

TInstantDateTime

Stores date and time values.

pascal
_CreatedAt: TInstantDateTime;

property CreatedAt: TDateTime read GetCreatedAt write SetCreatedAt;

Properties:

  • Value: TDateTime - The datetime value

TInstantDate

Stores date-only values (time is 0).

pascal
_BirthDate: TInstantDate;

property BirthDate: TDateTime read GetBirthDate write SetBirthDate;

Properties:

  • Value: TDateTime - The date value (time portion ignored)

TInstantTime

Stores time-only values (date is 0).

pascal
_StartTime: TInstantTime;

property StartTime: TDateTime read GetStartTime write SetStartTime;

Properties:

  • Value: TDateTime - The time value (date portion ignored)

Complex Attribute Classes

TInstantBlob

Stores binary data.

pascal
_Data: TInstantBlob;

property Data: TInstantBlob read GetData;

// Usage
Contact.Data.LoadFromFile('document.pdf');
Contact.Data.SaveToFile('output.pdf');

Methods:

  • LoadFromFile(FileName: string)
  • SaveToFile(FileName: string)
  • LoadFromStream(Stream: TStream)
  • SaveToStream(Stream: TStream)

TInstantMemo

Stores large text data.

pascal
_Notes: TInstantMemo;

property Notes: string read GetNotes write SetNotes;

// Or access as TStrings
property NoteLines: TStrings read GetNoteLines;

Properties:

  • Value: string - The text content
  • AsString: string - Same as Value

TInstantGraphic

Stores image data (BMP, JPG, PNG, etc).

pascal
_Photo: TInstantGraphic;

property Photo: TInstantGraphic read GetPhoto;

// Usage
Contact.Photo.LoadFromFile('photo.jpg');
Image1.Picture.Assign(Contact.Photo);

Methods:

  • Assign(Source: TPersistent)
  • LoadFromFile(FileName: string)
  • SaveToFile(FileName: string)

Relational Attribute Classes

TInstantReference

One-to-one relationship (reference to another object).

pascal
TContact = class(TInstantObject)
  _Category: TInstantReference;
published
  property Category: TCategory read GetCategory write SetCategory;
end;

function TContact.GetCategory: TCategory;
begin
  Result := _Category.Value as TCategory;
end;

procedure TContact.SetCategory(Value: TCategory);
begin
  _Category.Value := Value;
end;

Properties:

  • Value: TInstantObject - Referenced object
  • ReferenceObject: string - Object ID (class#id format)
  • ObjectClass: TInstantObjectClass - Referenced class type

Methods:

  • DestroyObject - Destroys referenced object without clearing reference
  • Reset - Clears reference

TInstantReferences

One-to-many relationship (collection of object references).

pascal
TCompany = class(TInstantObject)
  _Employees: TInstantReferences;
published
  property Employees: TInstantReferences read GetEmployees;
end;

// Usage
Company.Employees.Add(Person1);
Company.Employees.Insert(0, Person2);
for I := 0 to Company.Employees.Count - 1 do
  ShowMessage(Company.Employees[I].Name);

Properties:

  • Count: Integer - Number of references
  • Items[Index: Integer]: TInstantObject - Indexed access

Methods:

  • Add(AObject: TInstantObject): Integer
  • Insert(Index: Integer; AObject: TInstantObject)
  • Delete(Index: Integer)
  • Remove(AObject: TInstantObject): Integer
  • Clear
  • IndexOf(AObject: TInstantObject): Integer

TInstantPart

One-to-one composition (owned object).

pascal
TOrder = class(TInstantObject)
  _ShippingAddress: TInstantPart;
published
  property ShippingAddress: TAddress read GetShippingAddress write SetShippingAddress;
end;

function TOrder.GetShippingAddress: TAddress;
begin
  Result := _ShippingAddress.Value as TAddress;
end;

Properties:

  • Value: TInstantObject - Owned object

Note: Part objects are automatically disposed when owner is disposed.

TInstantParts

One-to-many composition (collection of owned objects).

pascal
TContact = class(TInstantObject)
  _Phones: TInstantParts;
published
  property Phones: TInstantParts read GetPhones;
end;

// Usage
var
  Phone: TPhone;
begin
  Phone := Contact.Phones.Add as TPhone;
  Phone.Number := '+1234567890';
  Phone.PhoneType := ptMobile;

  Contact.Store;  // Phones are automatically saved
end;

Properties:

  • Count: Integer - Number of parts
  • Items[Index: Integer]: TInstantObject - Indexed access

Methods:

  • Add: TInstantObject - Creates and adds new part
  • Insert(Index: Integer): TInstantObject
  • Delete(Index: Integer)
  • Remove(AObject: TInstantObject): Integer
  • Clear

TInstantConnector

Base class for database connectors.

Key Properties:

PropertyTypeDescription
IsDefaultBooleanSet as default connector
ConnectedBooleanConnection status
BrokerClassTInstantBrokerClassBroker class type
BrokerTInstantBrokerBroker instance
UseTransactionsBooleanEnable transaction support
OnConnectTNotifyEventFired when connected
OnDisconnectTNotifyEventFired when disconnected

Key Methods:

pascal
procedure Connect;
procedure Disconnect;
procedure StartTransaction;
procedure CommitTransaction;
procedure RollbackTransaction;
function CreateBroker: TInstantBroker;

Example:

pascal
var
  Connector: TInstantFireDACConnector;
begin
  Connector := TInstantFireDACConnector.Create(nil);
  try
    Connector.Connection := FDConnection1;
    Connector.IsDefault := True;
    Connector.Connect;

    // Now all objects use this connector by default
    var Contact := TContact.Create;
    try
      Contact.Store;
    finally
      Contact.Free;
    end;
  finally
    Connector.Free;
  end;
end;

TInstantObjectStore

Object cache manager (singleton).

Key Methods:

pascal
class function CurrentStore: TInstantObjectStore;
function Find(const AObjectClass: TInstantObjectClass; const AObjectId: string): TInstantObject;
procedure Add(AObject: TInstantObject);
procedure Remove(AObject: TInstantObject);
procedure Clear;

Example:

pascal
var
  Store: TInstantObjectStore;
  CachedContact: TContact;
begin
  Store := TInstantObjectStore.CurrentStore;

  // Check if object is in cache
  CachedContact := Store.Find(TContact, 'CONT001') as TContact;
  if Assigned(CachedContact) then
    ShowMessage('Object found in cache');
end;

Helper Functions

pascal
// Generate unique ID
function InstantGenerateId: string;

// Default connector
function InstantDefaultConnector: TInstantConnector;

// Find attribute in object path
function InstantFindAttribute(AObject: TInstantObject; const APath: string): TInstantAttribute;

// Get object class by name
function InstantGetClass(const AClassName: string): TInstantObjectClass;

// Register object class
procedure InstantRegisterClass(AClass: TInstantObjectClass);

Best Practices

  1. Always free objects - Call Free when done with objects (unless owned by Part/Parts)
  2. Use try-finally blocks - Ensure proper cleanup
  3. Store before freeing - Save changes before disposing objects
  4. Check IsOwned - Don't free objects owned by others
  5. Use default connector - Set IsDefault := True on one connector
  6. Handle exceptions - Wrap Store/Retrieve in try-except
  7. Validate in BeforeStore - Override BeforeStore for validation

See Also

Released under Mozilla License, Version 2.0.