Events
Aurelius provides an event system which you can use to receive callback notifications when some events occur, for example, an entity update or a item is included in a collection. This chapter explains how to use this event system and what events are available.
Using Events
Subscribing from code
Events in Aurelius are available in the Events property of the
TMappingExplorer object. Such
property refers to a TManagerEvents (declared in unit
Aurelius.Events.Manager
) object with several subproperties, each to them
related to an event. For example, to access the OnInserted event of the
default TMappingExplorer:
uses {...}, Aurelius.Mapping.Explorer, Aurelius.Events.Manager;
TMappingExplorer.Default.Events.OnInserted.Subscribe(
procedure(Args: TInsertedArgs)
begin
// Use Args.Entity to retrieve the inserted entity
end
);
TMappingExplorer.Default.Events.OnUpdated.Subscribe(
procedure(Args: TUpdatedArgs)
begin
// Use Args.Entity to retrieve the updated entity
end
);
In a less direct way, using method reference instead of anonymous method:
uses {...}, Aurelius.Mapping.Explorer, Aurelius.Events.Manager;
procedure TSomeClass.MyInsertedProc(Args: TInsertedArgs);
begin
// Use Args.Entity to retrieve the inserted entity
end;
procedure TSomeClass.MyUpdatedProc(Args: TUpdatedArgs);
begin
// Use Args.Entity to retrieve the updated entity
end;
procedure TSomeClass.RegisterMyEventListeners;
var
Events: TManagerEvents;
begin
Events := TMappingExplorer.Default.Events;
Events.OnInserted.Subscribe(MyInsertedProc);
Events.OnUpdated.Subscribe(MyUpdatedProc);
end;
The events are available in the TMappingExplorer object so the listeners will receive notifications about any event fired by any TObjectManager created that references the specified TMappingExplorer object. In other words, the events are "global" for that mapping explorer.
Listeners are method references that receive a single object as a parameter. Such object has several properties containing relevant information about the event, and differ for each event type. Names of event properties, method reference type and arguments follow a standard. The event property is named "On<event>", method reference type is "T<event>Proc" and parameter object is "T<event>Args". For example, for the "Deleted" event, the respective names will be "OnDeleted", "TDeletedProc" and "TDeletedArgs".
All events in Aurelius are multicast events, which means you can add several events handlers (listeners) to the same event. When an event occurs, all listeners will be notified. This allows you to add a listener in a safe way, without worrying if it will replace an existing listener that might have been set by other part of the application. You should use Subscribe and Unsubscribe methods to add and remove listeners, respectively. Note that since listeners are method references, you must sure to unsubscribe the same reference you subscribed to:
var
LocalProc: TInsertedProc;
begin
LocalProc := MyInsertedProc;
Events.OnInserted.Subscribe(LocalProc);
{...}
Events.OnInserted.Unsubscribe(LocalProc);
end;
Passing just the method name doesn't work:
Events.OnInserted.Subscribe(MyInsertedProc);
{...}
// this will NOT unsubscribe the previous subscription:
Events.OnInserted.Unsubcribe(MyInsertedProc);
TAureliusModelEvents Component
An alternative, more RAD way to use events is the TAureliusModelEvents component. Just drop the component in the form and double click the desired event in the object inspector to create an event handler.
The events available are exactly the same ones that you can set from code, like OnInserting, OnSqlExecuting, etc. See all the available events in this chapter.
Key properties
Name | Description |
---|---|
ModelName: string | The name(s) of the model(s) to be used by the manager. You can leave it blank, if you do it will use the default model. Two or more model names should be separated by comma. From the model names it will get the property TMappingExplorer component that will be passed to the TDatabaseManager constructor to create the instance that will be encapsulated. |
Note the events are "cumulative", the same way you do it from code. It means that if you add two or more TAureliusModelEvents in your application and set an event handler for the same event in all of them, all the handlers will be fired. That's very convenient to event handler code that is specific to each context in your app.
Using Attributes
A third and even more straightforward way to respond to events is to use attributes. You can simply add an attribute to a method of an entity class, and that method will be invoked when the event is triggered. Consider the following example:
type
{$RTTI EXPLICIT METHODS([vcPrivate..vcPublished])}
TCustomer = class
strict private
[OnInserting] procedure OnInserting(Args: TInsertingArgs);
[OnInserted] procedure OnInserted;
[OnUpdated, OnInserted] procedure AfterModification;
{...}
end;
When TCustomer
entity is about to be inserted in the database, the OnInserting
method will be invoked. After the record is inserted, the method OnInserted
is invoked.
Warning
By default, Delphi doesn't generate RTTI for non-published methods. That's why you must add the directive {$RTTI EXPLICIT METHODS([vcPrivate..vcPublished])}
to your class. If you don't do that, Aurelius won't know about the mentioned methods and they will not be invoked when the events are triggered!
Note that you can use the same method to handle more than one event. The method AfterModification
will be invoked when event OnUpdated
is fired, and also when OnInserted
is fired.
Finally, you can use two different signatures for the methods: the method can receive a single Args
parameters of the type of the event (see the available events below).
Alternatively, you can declare the method without specifying any parameter. This is useful if you don't need any information from event arguments and you want to keep your class as clean as possible (no dependency on a specific event type).
Available events
OnInserting Event
Occurs right before an entity is inserted (create) in the database. Note that the event is fired for every entity that is about to be inserted. For example, a single Manager.Save call might cause several entities to be inserted, due to cascades defined in the associations. In this case the event will be fired multiple times, one for each saved entity, even when the developer only called Save once.
Example:
TMappingExplorer.Default.Events.OnInserting.Subscribe(
procedure(Args: TInsertingArgs)
begin
// code here
end
);
TInsertingArgs Properties
Name | Description |
---|---|
Manager: TBaseObjectManager | The TObjectManager object which fired the event. |
Entity: TObject | The entity about to be inserted. |
Master: TMasterObjectValue | The parent object of the object being inserted. This property comes with a value in the case of list items (ManyValuedAssociation) that don't have a reference back to parent (unidirectional). TMasterObjectValue has two relevant properties: "MasterObject" which is the instance of parent object, and "MasterAssocMember" which is the name of the list property the item being inserted belongs to (for example, "InvoiceItems"). |
OnInserted Event
Occurs right after an entity is inserted (create) in the database. Note that the event is fired for every entity inserted. For example, a single Manager.Save call might cause several entities to be inserted, due to cascades defined in the associations. In this case the event will be fired multiple times, one for each saved entity, even when the developer only called Save once.
Example:
TMappingExplorer.Default.Events.OnInserted.Subscribe(
procedure(Args: TInsertedArgs)
begin
// code here
end
);
TInsertedArgs Properties
Name | Description |
---|---|
Manager: TBaseObjectManager | The TObjectManager object which fired the event. |
Entity: TObject | The entity that was inserted. |
Master: TMasterObjectValue | The parent object of the object being inserted. This property comes with a value in the case of list items (ManyValuedAssociation) that don't have a reference back to parent (unidirectional). TMasterObjectValue has two relevant properties: "MasterObject" which is the instance of parent object, and "MasterAssocMember" which is the name of the list property the item being inserted belongs to (for example, "InvoiceItems"). |
OnUpdating Event
Occurs right before an entity is about to be updated in the database.
Example:
TMappingExplorer.Default.Events.OnUpdating.Subscribe(
procedure(Args: TUpdatingArgs)
begin
// code here
end
);
TUpdatingArgs Properties
Name | Description |
---|---|
Manager: TBaseObjectManager | The TObjectManager object which fired the event. |
Entity: TObject | The entity that is going to be updated. |
OldColumnValues: TDictionary<string, Variant> | Represents the old object state using column name/value pairs. Don't confuse it with property names/values. For example, if the object has a property named "Name" that is mapped to a column database "CUSTOMER_NAME", the dictionary will contain "CUSTOMER_NAME" in the string key, and the respective value. Thus, associations are also represented by the foreign key column names/values. |
NewColumnValues: TDictionary<string, Variant> | Same as OldColumnValues, but contains the new state values. Comparing what has changed between NewColumnValues and OldColumnValues will give you the names of the columns that will be updated in the database. |
ChangedColumnNames: TList<string> | Contains a list of names of all columns that will be updated in the UPDATE statement. |
RecalculateState: Boolean | If you have changed any property value of the entity that is about to be updated, you need to set RecalculateState to True to force Aurelius to recalculate the columns that were modified and update the object state in the manager cache. For better performance, leave it false if you haven't modified any property. |
OnUpdated Event
Occurs right after an entity is updated in the database.
Example:
TMappingExplorer.Default.Events.OnUpdated.Subscribe(
procedure(Args: TUpdatedArgs)
begin
// code here
end
);
TUpdatedArgs Properties
Name | Description |
---|---|
Manager: TBaseObjectManager | The TObjectManager object which fired the event. |
Entity: TObject | The entity that was updated. |
OldColumnValues: TDictionary<string, Variant> | Represents the old object state using column name/value pairs. Don't confuse it with property names/values. For example, if the object has a property named "Name" that is mapped to a column database "CUSTOMER_NAME", the dictionary will contain "CUSTOMER_NAME" in the string key, and the respective value. Thus, associations are also represented by the foreign key column names/values. |
NewColumnValues: TDictionary<string, Variant> | Same as OldColumnValues, but contains the new state values. Comparing what has changed between NewColumnValues and OldColumnValues will give you the names of the columns that will be updated in the database. |
ChangedColumnNames: TList<string> | Contains a list of names of all columns that were updated in the UPDATE statement. |
OnDeleting Event
Occurs right before an entity is about to be deleted from the database. Note that the event is fired for every entity deleted. For example, a single Manager.Remove call might cause several entities to be deleted, due to cascades defined in the associations. In this case the event will be fired multiple times, one for each deleted entity, even when the developer only called Remove once.
Example:
TMappingExplorer.Default.Events.OnDeleting.Subscribe(
procedure(Args: TDeletingArgs)
begin
// code here
end
);
TDeletingArgs Properties
Name | Description |
---|---|
Manager: TBaseObjectManager | The TObjectManager object which fired the event. |
Entity: TObject | The entity about to be deleted. |
OnDeleted Event
Occurs right after an entity is deleted from the database. Note that the event is fired for every entity deleted. For example, a single Manager.Remove call might cause several entities to be deleted, due to cascades defined in the associations. In this case the event will be fired multiple times, one for each deleted entity, even when the developer only called Remove once.
When the event is fired, the entity object is still a valid reference, but will be destroyed right after the event listener returns.
Example:
TMappingExplorer.Default.Events.OnDeleted.Subscribe(
procedure(Args: TDeletedArgs)
begin
// code here
end
);
TDeletedArgs Properties
Name | Description |
---|---|
Manager: TBaseObjectManager | The TObjectManager object which fired the event. |
Entity: TObject | The deleted entity. |
OnCollectionItemAdded Event
Occurs when an item is added to a collection, at database level. In other words, when the foreign key of an item entity is set to point to the parent entity.
Example:
TMappingExplorer.Default.Events.OnCollectionItemAdded.Subscribe(
procedure(Args: TCollectionItemAddedArgs)
begin
// code here
end
);
TCollectionItemAddedArgs Properties
Name | Description |
---|---|
Manager: TBaseObjectManager | The TObjectManager object which fired the event. |
Parent: TObject | The parent entity which contains the collection where the item was added to. |
Item: TObject | The item entity added to the collection. |
MemberName: string | The member name (field or property) of the parent entity that holds the collection. |
OnCollectionItemRemoved Event
Occurs when an item is removed from a collection, at database level. In other words, when the foreign key of an item entity is set to null (or to a different parent entity).
Example:
TMappingExplorer.Default.Events.OnCollectionItemRemoved.Subscribe(
procedure(Args: TCollectionItemRemovedArgs)
begin
// code here
end
);
TCollectionItemRemovedArgs Properties
Name | Description |
---|---|
Manager: TBaseObjectManager | The TObjectManager object which fired the event. |
Parent: TObject | The parent entity which contains the collection where the item was removed from. |
Item: TObject | The item entity removed from the collection. |
MemberName: string | The member name (field or property) of the parent entity that holds the collection. |
OnSqlExecuting Event
Occurs right before an SQL statement is executed.
Example:
TMappingExplorer.Default.Events.OnSqlExecuting.Subscribe(
procedure(Args: TSQLExecutingArgs)
begin
// code here
end
);
TSQLExecutingArgs Properties
Name | Description |
---|---|
SQL: string | The SQL statement that will be executed. |
Params: TEnumerable<TDBParam> | A list of TDBParam objects used for the SQL statement execution. The TDBParam object has the properties ParamName, ParamType and ParamValue. |