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.