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 managementTInstantObjectStore- Object caching and lifecycle management
Key Classes
TInstantObject
Base class for all persistent business objects in InstantObjects.
Inheritance: TInstantStreamable → TInstantObject
Key Properties:
| Property | Type | Description |
|---|---|---|
Id | string | Unique identifier for the object |
PersistentId | string | Original ID when object was retrieved |
UpdateCount | Integer | Optimistic locking counter |
IsChanged | Boolean | True if object has unsaved changes |
IsPersistent | Boolean | True if object exists in storage |
IsOwned | Boolean | True if object is owned by another |
Connector | TInstantConnector | Database connector for this object |
Key Methods:
// 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:
OnAfterCreate: TNotifyEvent;
OnAfterRetrieve: TNotifyEvent;
OnBeforeStore: TNotifyEvent;
OnAfterStore: TNotifyEvent;
OnBeforeDispose: TNotifyEvent;
OnAfterDispose: TNotifyEvent;
OnAttributeChanged: TInstantAttributeChangeEvent;
OnIdChanged: TInstantIdChangeEvent;Example Usage:
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:
| Property | Type | Description |
|---|---|---|
Name | string | Attribute name |
Owner | TInstantObject | Owning object |
IsChanged | Boolean | True if value changed |
IsRequired | Boolean | True if value required |
IsDefault | Boolean | True if default value |
Metadata | TInstantAttributeMetadata | Attribute metadata |
Simple Attribute Classes
TInstantString
Stores string values.
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 valueSize: Integer- Maximum length from metadata
TInstantInteger
Stores integer values.
_Age: TInstantInteger;
property Age: Integer read GetAge write SetAge;Properties:
Value: Integer- The integer value
TInstantFloat
Stores floating-point values.
_Price: TInstantFloat;
property Price: Double read GetPrice write SetPrice;Properties:
Value: Double- The float value
TInstantCurrency
Stores currency values with precision.
_Salary: TInstantCurrency;
property Salary: Currency read GetSalary write SetSalary;Properties:
Value: Currency- The currency value
TInstantBoolean
Stores boolean values.
_Active: TInstantBoolean;
property Active: Boolean read GetActive write SetActive;Properties:
Value: Boolean- The boolean value
TInstantDateTime
Stores date and time values.
_CreatedAt: TInstantDateTime;
property CreatedAt: TDateTime read GetCreatedAt write SetCreatedAt;Properties:
Value: TDateTime- The datetime value
TInstantDate
Stores date-only values (time is 0).
_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).
_StartTime: TInstantTime;
property StartTime: TDateTime read GetStartTime write SetStartTime;Properties:
Value: TDateTime- The time value (date portion ignored)
TInstantTimeStamp
New in 4.4.0. Stores date and time with the highest precision supported by the database (data type dtTimeStamp). It descends from TInstantDateTime, so it has the same properties and conversions; only the column type changes. With the FireDAC broker the column is DATETIME2(7) on MS SQL Server (where DateTime attributes use DATETIME2(3)), TIMESTAMP(6) on Oracle and PostgreSQL, DATETIME(6) on MySQL and TIMESTAMP on Firebird/InterBase and SQLite. The other brokers use the same column type of DateTime.
TContact = class(TInstantObject)
{IOMETADATA stored;
Name: String(50) index;
ObjectTimeStamp: TimeStamp; }
_Name: TInstantString;
_ObjectTimeStamp: TInstantTimeStamp;
...
// Read-only property: the value is set by the business object
property ObjectTimeStamp: TDateTime read GetObjectTimeStamp;
procedure TContact.BeforeStore;
begin
inherited;
// when the contact has been stored (created or changed) the last time
_ObjectTimeStamp.Value := Now;
end;Properties:
Value: TDateTime- The date and time value (milliseconds precision on the Delphi side)
Complex Attribute Classes
TInstantBlob
Stores binary data.
_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.
_Notes: TInstantMemo;
property Notes: string read GetNotes write SetNotes;
// Or access as TStrings
property NoteLines: TStrings read GetNoteLines;Properties:
Value: string- The text contentAsString: string- Same as Value
TInstantGraphic
Stores image data (BMP, JPG, PNG, etc).
_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).
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 objectReferenceObject: string- Object ID (class#id format)ObjectClass: TInstantObjectClass- Referenced class type
Methods:
DestroyObject- Destroys referenced object without clearing referenceReset- Clears reference
TInstantReferences
One-to-many relationship (collection of object references).
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 referencesItems[Index: Integer]: TInstantObject- Indexed access
Methods:
Add(AObject: TInstantObject): IntegerInsert(Index: Integer; AObject: TInstantObject)Delete(Index: Integer)Remove(AObject: TInstantObject): IntegerClearIndexOf(AObject: TInstantObject): Integer
TInstantPart
One-to-one composition (owned object).
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).
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 partsItems[Index: Integer]: TInstantObject- Indexed access
Methods:
Add: TInstantObject- Creates and adds new partInsert(Index: Integer): TInstantObjectDelete(Index: Integer)Remove(AObject: TInstantObject): IntegerClear
TInstantConnector
Base class for database connectors.
Key Properties:
| Property | Type | Description |
|---|---|---|
IsDefault | Boolean | Set as default connector |
Connected | Boolean | Connection status |
BrokerClass | TInstantBrokerClass | Broker class type |
Broker | TInstantBroker | Broker instance |
UseTransactions | Boolean | Enable transaction support |
OnConnect | TNotifyEvent | Fired when connected |
OnDisconnect | TNotifyEvent | Fired when disconnected |
Key Methods:
procedure Connect;
procedure Disconnect;
procedure StartTransaction;
procedure CommitTransaction;
procedure RollbackTransaction;
function CreateBroker: TInstantBroker;Example:
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:
class function CurrentStore: TInstantObjectStore;
function Find(const AObjectClass: TInstantObjectClass; const AObjectId: string): TInstantObject;
procedure Add(AObject: TInstantObject);
procedure Remove(AObject: TInstantObject);
procedure Clear;Example:
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
// 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
- Always free objects - Call
Freewhen done with objects (unless owned by Part/Parts) - Use try-finally blocks - Ensure proper cleanup
- Store before freeing - Save changes before disposing objects
- Check IsOwned - Don't free objects owned by others
- Use default connector - Set
IsDefault := Trueon one connector - Handle exceptions - Wrap Store/Retrieve in try-except
- Validate in BeforeStore - Override
BeforeStorefor validation
See Also
- InstantBrokers - Broker architecture
- InstantMetadata - Metadata system
- InstantPresentation - Exposer and Selector
- User Guide - Creating Objects - Creating objects tutorial
- User Guide - Retrieving Objects - Retrieving objects tutorial
