Added Event

Summary

The Added event fires when a new entity instance is created in a data context. Use it to initialize dynamic properties, create related child entities, or perform setup logic that depends on runtime data (such as the current date or user).

When does it fire?

The Added event fires when new Entity(context) is called — that is, when a new entity is constructed with an EventContext or IDataContext. It runs once per entity creation.

Syntax

salesOrder.OnAdded().Do((entity, args) => { /* logic */ });

Do overloads

Signature Description
.Do(entity => { }) Run logic with access to the entity
.Do((entity, args) => { }) Run logic with access to the entity and services/data via args

Scenarios

1. Setting the order date to today

When a new sales order is created, default the order date to the current date.

[Logic]
public class SalesOrderBL(SalesOrder.Logic salesOrder)
{
    [RegisterLogic]
    public void SetOrderDate()
    {
        salesOrder.OnAdded().Do(o =>
            o.OrderDate = DateOnly.FromDateTime(DateTime.UtcNow));
    }
}

Note: Do NOT use OnAdded for static default values like Quantity = 1. Use the [DefaultValue(1)] attribute instead.

2. Creating a main UOM when a product is created

When a new product is created, automatically add its main unit of measure if one does not already exist.

[Logic]
public class ProductBL(Product.Logic product)
{
    [RegisterLogic]
    public void CreateMainUom()
    {
        product.OnAdded().Do((p, args) =>
        {
            if (p.Uoms.Count == 0 || !p.Uoms.Any(u => u.Operation == UomOperation.Main))
            {
                var context = args.Context;
                var mainUom = new ProductUom(context)
                {
                    Product = p,
                    Factor = 1,
                    Operation = UomOperation.Main,
                    SellableOption = SellableOption.DefaultSellingUnit
                };
            }
        });
    }
}

3. Initializing a newly created customer

When a new customer is created, set up initial properties based on the environment.

[Logic]
public class CustomerBL(Customer.Logic customer)
{
    [RegisterLogic]
    public void InitializeNewCustomer()
    {
        customer.OnAdded().Do((c, args) =>
        {
            c.CreatedDate = DateOnly.FromDateTime(DateTime.UtcNow);
            c.Status = CustomerStatus.Active;
        });
    }
}

4. Copying defaults from a parent entity

When a new sales order detail is added, carry forward settings from the order header.

[Logic]
public class SalesOrderDetailBL(SalesOrderDetail.Logic salesOrderDetail)
{
    [RegisterLogic]
    public void InheritOrderDefaults()
    {
        salesOrderDetail.OnAdded().Do((detail, args) =>
        {
            if (detail.SalesOrder != null)
                detail.DiscountPercent = detail.SalesOrder.DefaultDiscountPercent;
        });
    }
}

5. Using a service to generate an ID on creation

When a contact is created, generate a unique ID using a sequence manager.

[Logic]
public class ContactBL(Contact.Logic contact)
{
    [RegisterLogic]
    public void GenerateContactId()
    {
        contact.OnAdded().Do((c, args) =>
        {
            var sequenceManager = args.GetService<ISequenceManager>();
            var nextVal = sequenceManager.GetNextSequenceValueAsync("ContactSequence").Result;
            c.Id = $"C-{nextVal:D6}";
        });
    }
}

Notes

  • OnAdded fires once on entity construction — it does not fire when loading an existing entity from the database.
  • Use OnAdded for dynamic defaults that depend on runtime context (current date, services, parent entity data).
  • For static literal defaults (e.g., Factor = 1), use the [DefaultValue] attribute on the property.
  • OnAdded has access to args.Context, args.GetService<T>(), and args.GetEntities<T>().