Events
Summary
The event system drives all business logic in the Benevia platform. Instead of writing imperative code in service layers, you declare rules on properties and entities using a fluent API. Events fire automatically during the property set pipeline, entity lifecycle, or on explicit invocation.
[Logic] and [RegisterLogic] are used to register subscribers when the server starts.
[Logic]
public class ProductAccessoryBL(ProductAccessory.Logic productAccessory)
{
[RegisterLogic]
public void ValidateQuantity()
{
productAccessory.Validate(a => a.Quantity)
.RejectIf(qty => qty < 1.0m)
.WithMessage("Quantity must be at least 1");
}
}
Pipelines
New entity: When a new entity is constructed with new Entity(context):
new Entity(context) → Added
Set Property: When a property value is set, events fire in this order:
Set property → ReadOnly → DataType AutoCorrect → Property AutoCorrect
→ DataType Validate → Property Validate → Dirty dependents → Changed
Read Property: When a property value is read, it checks to see if it is dirty. If yes, then it computes or gets the default value. Compute and default behave in the same way.
Get property → Compute/Default
Delete: When an entity is deleted.
Delete request → Deleting → Entity removed → Deleted
Save changes: When SaveChanges() is called on the context:
SaveChanges() → PreSave → Entity Validate → Compute dirty persisted properties → Write to database
Event Reference
Add and Delete Pipeline
| Event | Description |
|---|---|
| Added | Fires when a new entity is created. Use for dynamic initialization (e.g., setting order date to today, creating child entities). |
| Deleting | Fires before an entity is removed. Use to prevent deletion or specify additional entities to cascade-delete. |
| Deleted | Fires after an entity is removed. Use for post-deletion cleanup, transferring responsibilities, or logging. |
Set Property Pipeline
| Event | Description |
|---|---|
| ReadOnly | Controls whether a property can be written to. If any read-only condition is true, the setter throws. |
| DataType AutoCorrect | Transforms values based on their data type — applies to all properties of that type (e.g., capitalizing proper nouns, trimming text). |
| AutoCorrect | Transforms or normalizes a specific property value before validation (e.g., uppercasing codes, rounding numbers). |
| DataType Validate | Validates values based on their data type — applies to all properties of that type (e.g., email format, non-negative decimals). |
| Validate | Validates a specific property value. Rejects invalid values and keeps the last valid value. |
| Changed | Runs after a property value is successfully set and validated. Use to synchronize related data or trigger side effects. |
| CollectionChanged | Fires when items in a child collection are added, removed, replaced, or cleared. Requires CollectionLoadMode.LoadAll. |
Read Property Pipeline
| Event | Description |
|---|---|
| Compute | Defines how a property is calculated from other properties. Lazily evaluated — only recalculates when dirty. |
| Default | Sets a property value when a trigger changes and the target is empty. For dynamic defaults from related data, not static literals. |
Save pipeline
| Event | Description |
|---|---|
| PreSave | Runs just before persisting. Use to populate fields that require save-time data (e.g., generating sequence numbers). |
| Entity Validate | Validates the entity as a whole during save. Use for cross-property or complex business rule validation. |
Methods
| Event | Description |
|---|---|
| Methods | Operations on entities exposed as OData endpoints via the [Method] attribute. Methods can be defined as static or per instance. |