| name | csharpessentials-entity |
| description | Use when building DDD domain models — EntityBase<TId> for aggregate roots with audit fields and domain events, SoftDeletableEntityBase for soft deletion lifecycle, and IDomainEvent for defining and raising domain events. |
CSharpEssentials.Entity
DDD base classes for aggregate roots. Built-in audit tracking, soft deletion, and domain event support.
Installation
dotnet add package CSharpEssentials.Entity
Namespaces
using CSharpEssentials.Entity;
using CSharpEssentials.Entity.Interfaces;
EntityBase<TId>
public class Order : EntityBase<Guid>
{
public string CustomerId { get; private set; } = default!;
public decimal Total { get; private set; }
public static Order Create(string customerId, decimal total)
{
var order = new Order { Id = Guid.NewGuid(), CustomerId = customerId, Total = total };
order.Raise(new OrderCreatedEvent(order.Id, customerId));
return order;
}
}
SoftDeletableEntityBase<TId>
public class Product : SoftDeletableEntityBase<int>
{
public string Name { get; private set; } = default!;
}
product.MarkAsDeleted(DateTimeOffset.UtcNow, "admin");
product.Restore();
product.MarkAsHardDeleted();
Domain Events
public record OrderCreatedEvent(Guid OrderId, string CustomerId) : IDomainEvent;
[DomainEventTiming(DomainEventTiming.BeforeSave)]
public record InventoryReservedEvent(Guid ProductId, int Qty) : IDomainEvent;
order.Raise(new OrderCreatedEvent(order.Id, customerId));
IReadOnlyList<IDomainEvent> events = order.DomainEvents;
order.ClearDomainEvents();
Best Practices
- Call
Raise() only inside entity methods — keep domain events encapsulated in the aggregate
DomainEvents is a property — do not call GetDomainEvents() (doesn't exist)
- Audit fields are
UpdatedAt/UpdatedBy — not ModifiedAt/ModifiedBy
MarkAsDeleted() takes two parameters: (DateTimeOffset deletedAt, string deletedBy)
- Use
DomainEventTiming.BeforeSave for events that must be processed before the transaction commits