This is the API specification for Entity and Aggregate related public types provided by the Functorium framework. For design principles and implementation patterns, see the Entity and Aggregate Implementation Guide .
Type Namespace Description IEntityFunctorium.Domains.EntitiesEntity naming convention constant definitions IEntity<TId>Functorium.Domains.EntitiesEntity base interface (ID-based equality contract) IEntityId<T>Functorium.Domains.EntitiesUlid-based Entity ID interface Entity<TId>Functorium.Domains.EntitiesEntity base abstract class (equality, proxy support) AggregateRoot<TId>Functorium.Domains.EntitiesAggregate Root base abstract class (domain event management) GenerateEntityIdAttributeFunctorium.Domains.EntitiesEntityId source generator trigger attribute IAuditableFunctorium.Domains.EntitiesCreated/modified timestamp tracking mixin IAuditableWithUserFunctorium.Domains.EntitiesCreated/modified timestamp + user tracking mixin IConcurrencyAwareFunctorium.Domains.EntitiesOptimistic concurrency control mixin ISoftDeletableFunctorium.Domains.EntitiesSoft delete mixin ISoftDeletableWithUserFunctorium.Domains.EntitiesSoft delete + deleter tracking mixin IDomainServiceFunctorium.Domains.ServicesDomain service marker interface
Interfaces defining the Entity contract.
const string CreateMethodName = "Create";
const string CreateFromValidatedMethodName = "CreateFromValidated";
Constant Value Description CreateMethodName"Create"Factory method name for creating a new Entity CreateFromValidatedMethodName"CreateFromValidated"Method name for restoring an Entity from validated data (for Repository/ORM)
public interface IEntity<TId> : IEntity
where TId : struct , IEntityId<TId>
Property Type Description IdTIdUnique identifier of the Entity
Generic constraint: TId must be a struct and implement IEntityId<TId>.
Interface for Ulid-based Entity IDs. Supports time-ordered sorting and inherits IEquatable<T>, IComparable<T>, IParsable<T>.
public interface IEntityId<T> : IEquatable<T>, IComparable<T>, IParsable<T>
where T : struct , IEntityId<T>
static abstract T Create (Ulid id);
static abstract T Create ( string id);
Member Return Type Description ValueUlidThe Ulid value New()TCreates a new EntityId (static abstract) Create(Ulid id)TCreates an EntityId from a Ulid (static abstract) Create(string id)TCreates an EntityId from a string (static abstract). Throws FormatException for invalid formats
Base abstract class for Entity providing ID-based equality comparison. Also handles ORM proxy types (Castle, NHibernate, EF Core Proxies).
public abstract class Entity <TId> : IEntity<TId>, IEquatable<Entity<TId>>
where TId : struct , IEntityId<TId>
Property Type Accessor Description IdTIdpublic get; protected initUnique identifier of the Entity
Signature Access Level Description Entity()protectedDefault constructor (for ORM/serialization) Entity(TId id)protectedCreates an Entity with a specified ID
Method Return Type Access Level Description Equals(object? obj)boolpublicID-based equality comparison (proxy-type aware) Equals(Entity<TId>? other)boolpublicType-safe equality comparison GetHashCode()intpublicID-based hash code operator ==(Entity<TId>?, Entity<TId>?)boolpublic staticEquality operator operator !=(Entity<TId>?, Entity<TId>?)boolpublic staticInequality operator CreateFromValidation<TEntity, TValue>(Validation<Error, TValue>, Func<TValue, TEntity>)Fin<TEntity>public staticFactory helper using LanguageExt Validation GetUnproxiedType(object obj)Typeprotected staticStrips ORM proxy and returns the actual type
public class Product : Entity<ProductId>
# pragma warning disable CS8618
# pragma warning restore CS8618
private Product (ProductId id, ProductName name) : base (id)
public ProductName Name { get ; private set ; }
public static Product Create (ProductName name)
=> new ( ProductId . New (), name);
public static Product CreateFromValidated (ProductId id, ProductName name)
Base abstract class for Aggregate Root providing domain event management. Inherits Entity<TId> and implements IDomainEventDrain (internal).
public abstract class AggregateRoot <TId> : Entity<TId>, IDomainEventDrain
where TId : struct , IEntityId<TId>
Property Type Accessor Description DomainEventsIReadOnlyList<IDomainEvent>public getDomain event list (read-only)
Signature Access Level Description AggregateRoot()protectedDefault constructor (for ORM/serialization) AggregateRoot(TId id)protectedCreates an Aggregate Root with a specified ID
Method Return Type Access Level Description AddDomainEvent(IDomainEvent domainEvent)voidprotectedAdds a domain event ClearDomainEvents()voidpublicRemoves all domain events (IDomainEventDrain implementation)
AggregateRoot<TId> separates two interfaces for domain events.
Interface Access Level Role IHasDomainEventspublicEvent read-only access (DomainEvents property) IDomainEventDraininternalEvent cleanup (ClearDomainEvents()) — infrastructure concern
public class Order : AggregateRoot<OrderId>
# pragma warning disable CS8618
# pragma warning restore CS8618
private Order (OrderId id, Money totalAmount) : base (id)
TotalAmount = totalAmount;
Status = OrderStatus . Pending ;
public Money TotalAmount { get ; private set ; }
public OrderStatus Status { get ; private set ; }
public static Order Create (Money totalAmount)
var order = new Order(id, totalAmount);
order . AddDomainEvent ( new OrderCreatedEvent(id, totalAmount));
public Fin<Unit> Confirm ()
if ( ! Status . CanTransitionTo ( OrderStatus . Confirmed ))
return Fin <Unit> . Fail ( Error . New ( " Cannot confirm order " ));
Status = OrderStatus . Confirmed ;
AddDomainEvent ( new OrderConfirmedEvent(Id));
When applied to an Entity class, the source generator automatically generates EntityId-related types.
[AttributeUsage( AttributeTargets . Class , AllowMultiple = false , Inherited = false )]
public sealed class GenerateEntityIdAttribute : Attribute;
Applying [GenerateEntityId] to the Product class generates the following types.
Generated Type Kind Description ProductIdreadonly partial record structUlid-based EntityId (implements IEntityId<ProductId>) ProductIdComparersealed classEF Core ValueComparer<ProductId> (for change tracking) ProductIdConvertersealed classEF Core ValueConverter<ProductId, string> (string conversion for DB storage)
Member Type/Return Description Nameconst stringType name constant ("ProductId") Namespaceconst stringNamespace constant Emptystatic readonly ProductIdEmpty value (based on Ulid.Empty) ValueUlid { get; init; }The Ulid value New()static ProductIdCreates a new ID Create(Ulid id)static ProductIdCreates from a Ulid Create(string id)static ProductIdCreates from a string (FormatException possible) CompareTo(ProductId other)intUlid-based comparison <, >, <=, >=boolComparison operators Parse(string, IFormatProvider?)static ProductIdIParsable<T> implementationTryParse(string?, IFormatProvider?, out ProductId)static boolIParsable<T> implementationToString()stringUlid string representation
Generated EntityIds automatically have [JsonConverter] and [TypeConverter] attributes applied, supporting JSON serialization and type conversion.
var productId = ProductId . New ();
var parsed = ProductId . Create ( " 01ARZ3NDEKTSV4RRFFQ69G5FAV " );
bool isNewer = productId > parsed;
builder . Property (x => x . Id )
. HasConversion ( new ProductIdConverter())
. Metadata . SetValueComparer ( new ProductIdComparer());
Interfaces that can be optionally mixed into Entity or Aggregate Root to add cross-cutting concerns.
Tracks creation/modification timestamps.
public interface IAuditable
DateTime CreatedAt { get ; }
Option<DateTime> UpdatedAt { get ; }
Property Type Description CreatedAtDateTimeCreation timestamp UpdatedAtOption<DateTime>Last modification timestamp (None if never modified)
Extends IAuditable to additionally track user information.
public interface IAuditableWithUser : IAuditable
Option< string > CreatedBy { get ; }
Option< string > UpdatedBy { get ; }
Property Type Description CreatedByOption<string>Creator identifier UpdatedByOption<string>Last modifier identifier
Manages row version for optimistic concurrency control. Maps to EF Core’s [Timestamp]/IsRowVersion().
public interface IConcurrencyAware
byte [] RowVersion { get ; }
Property Type Description RowVersionbyte[]Row version for optimistic concurrency control
Supports soft delete. IsDeleted provides a default implementation (default interface method) derived from DeletedAt.
public interface ISoftDeletable
Option<DateTime> DeletedAt { get ; }
bool IsDeleted => DeletedAt . IsSome ;
Property Type Description DeletedAtOption<DateTime>Deletion timestamp (None if not deleted) IsDeletedboolWhether deleted (derived from DeletedAt.IsSome, default implementation)
Extends ISoftDeletable to additionally track deleter information.
public interface ISoftDeletableWithUser : ISoftDeletable
Option< string > DeletedBy { get ; }
Property Type Description DeletedByOption<string>Deleter identifier
public class Product : AggregateRoot<ProductId>, IAuditableWithUser, ISoftDeletable, IConcurrencyAware
public DateTime CreatedAt { get ; private set ; }
public Option<DateTime> UpdatedAt { get ; private set ; }
public Option< string > CreatedBy { get ; private set ; }
public Option< string > UpdatedBy { get ; private set ; }
public Option<DateTime> DeletedAt { get ; private set ; }
public byte [] RowVersion { get ; private set ; } = [];
A marker interface for expressing domain logic that spans multiple Aggregates.
public interface IDomainService { }
Rule Description Stateless Does not maintain mutable state between calls (Evans Blue Book Ch.9) Default pattern Implemented as pure functions (no external I/O) Repository dependency allowed May depend on Repository interfaces for large-scale cross-data queries Port/Adapter forbidden No IObservablePort dependency (Port/Adapter is used in Usecases) Location Domain Layer
public sealed class PricingService : IDomainService
public static Fin<Money> CalculateDiscount (
// Pure function logic that references values from multiple Aggregates
var discount = originalPrice . Value * rate . Value * grade . Multiplier ;
return Money . Create ( originalPrice . Value - discount);