Lazy Loading¶
Trysil supports deferred loading of related entities through TTLazy<T> and TTLazyList<T>, both defined in Trysil.Lazy.pas. Related data is loaded from the database only when first accessed, avoiding unnecessary queries for relations that may never be used.
TTLazy\<T> (Single Entity)¶
Use TTLazy<T> for a many-to-one relationship where a field references a single related entity.
Entity Definition¶
[TTable('Employees')]
[TSequence('EmployeesID')]
TEmployee = class
strict private
[TPrimaryKey]
[TColumn('ID')]
FID: TTPrimaryKey;
[TColumn('CompanyID')]
FCompany: TTLazy<TCompany>;
[TVersionColumn]
[TColumn('VersionID')]
FVersionID: TTVersion;
function GetCompany: TCompany;
procedure SetCompany(const AValue: TCompany);
public
property ID: TTPrimaryKey read FID;
property Company: TCompany read GetCompany write SetCompany;
end;
Getter and Setter¶
function TEmployee.GetCompany: TCompany;
begin
Result := FCompany.Entity;
end;
procedure TEmployee.SetCompany(const AValue: TCompany);
begin
FCompany.Entity := AValue;
end;
Behavior¶
- The related entity is loaded on the first access to
.Entity. Subsequent accesses return the cached instance. - Setting
.Entityto a different object updates the internal foreign key ID and frees the previous entity (unless the identity map is active). - When the
IDproperty on the lazy field changes, the cached entity is cleared and will be reloaded on next access.
TTLazyList\<T> (Collection)¶
Use TTLazyList<T> for a one-to-many relationship where a parent entity has multiple children.
Entity Definition¶
[TTable('Departments')]
[TSequence('DepartmentsID')]
TDepartment = class
strict private
[TPrimaryKey]
[TColumn('ID')]
FID: TTPrimaryKey;
[TColumn('DepartmentID')]
FEmployees: TTLazyList<TEmployee>;
function GetEmployees: TTList<TEmployee>;
public
property ID: TTPrimaryKey read FID;
property Employees: TTList<TEmployee> read GetEmployees;
end;
Getter¶
Behavior¶
- The list is loaded on the first access to
.List. A SELECT query is executed with a filter matching the foreign key column to the parent's ID. AddEntitycreates a new entity via the context and adds it to the list:
- When the parent's ID changes, the cached list is freed and will be reloaded on next access.
Important Notes¶
-
Context lifetime -- Both
TTLazy<T>andTTLazyList<T>hold a reference to the owningTTContext. The context must remain alive for as long as lazy fields may be accessed. Accessing a lazy field after the context is freed will cause an access violation. -
Identity map interaction -- When
UseIdentityMapisTrue, lazy-loaded entities are not freed by the lazy wrapper (the identity map owns them). WhenUseIdentityMapisFalse, the lazy wrapper owns and frees loaded entities on destruction or when the ID changes. -
Used with TRelation -- Lazy loading is typically combined with the
TRelationattribute on the parent entity class to declare the referential integrity constraint:
- N+1 query pattern -- Be aware that accessing lazy fields in a loop generates one query per entity. For bulk operations, consider loading related data upfront with a filtered
Select<T>call.