Deleted Event
Summary
The Deleted event fires after an entity has been removed from the data context. Use it for post-deletion cleanup, transferring responsibilities to other entities, or logging. The deletion cannot be cancelled at this point — use the Deleting event if you need to prevent deletion.
When does it fire?
The Deleted event fires after the entity and any AlsoDelete entities have been successfully removed from the context. The entity data is still accessible in the event handler, but the entity is no longer tracked by the context.
Delete request → Deleting (can abort) → Entity removed → Deleted (post-cleanup)
Syntax
productUom.OnDeleted().Do(deletedArgs => { /* logic */ });
Do overloads
| Signature | Description |
|---|---|
.Do(args => { }) |
React to the deletion via args.Entity to access the deleted entity |
The args parameter provides:
args.Entity— the entity that was just deleted (still readable but no longer tracked)
Scenarios
1. Transferring the default selling unit designation
When a UOM that was the default selling unit is deleted, transfer that designation to the product's main UOM so there is always a default.
[Logic]
public class ProductUomBL(ProductUom.Logic productUom)
{
[RegisterLogic]
public void TransferDefaultSellingUnit()
{
productUom.OnDeleted().Do(c =>
{
if (c.Entity.SellableOption == SellableOption.DefaultSellingUnit)
{
var mainUom = c.Entity.Product?.Uoms
.FirstOrDefault(u => u.Operation == UomOperation.Main);
if (mainUom != null)
mainUom.SellableOption = SellableOption.DefaultSellingUnit;
}
});
}
}
2. Logging the deletion of a customer
Record when a customer entity is removed for audit purposes.
[Logic]
public class CustomerBL(Customer.Logic customer)
{
[RegisterLogic]
public void LogDeletion()
{
customer.OnDeleted().Do(c =>
{
var logger = c.GetService<ILogger<CustomerBL>>();
logger.LogInformation("Customer {Id} ({Name}) was deleted",
c.Entity.Id, c.Entity.FullName);
});
}
}
3. Cleaning up orphaned contacts
When a customer is deleted, check whether the primary contact is used by any other entity. If not, mark it for review.
[Logic]
public class CustomerBL(Customer.Logic customer)
{
[RegisterLogic]
public void FlagOrphanedContacts()
{
customer.OnDeleted().Do(c =>
{
var contact = c.Entity.PrimaryContact;
if (contact == null) return;
var stillReferenced = c.GetEntities<Customer>()
.Any(cust => cust.PrimaryContact == contact);
if (!stillReferenced)
contact.Status = ContactStatus.NeedsReview;
});
}
}
Deleted vs. Deleting
| Deleting | Deleted | |
|---|---|---|
| When | Before removal | After removal |
| Can cancel? | Yes (AbortIf) |
No |
| Can delete others? | Yes (AlsoDelete) |
No — use Deleting for that |
| Use for | Prevention, cascading deletes | Cleanup, logging, state transfer |
Notes
- Do not use
OnDeletedto delete related entities. UseOnDeleting().AlsoDelete()instead. - Do not use
OnDeletedto update aggregates. Use Compute with.DirtyWithRelation(o => o.Details).DirtyBy(...)to update aggregates when a child entity is deleted. - The deleted entity's properties are still readable in the handler, but the entity is no longer part of the data context.
OnDeletedruns after allAlsoDeleteentities have been removed.