Table of Contents

Class Entity<TId>

Namespace
FunctionalDdd
Assembly
FunctionalDdd.DomainDrivenDesign.dll

Base class for entities in Domain-Driven Design. An entity is a domain object defined by its identity rather than its attributes. Two entities with different attributes but the same ID are considered equal.

public abstract class Entity<TId> where TId : notnull

Type Parameters

TId

The type of the entity's unique identifier. Must be non-nullable.

Inheritance
Entity<TId>
Derived
Inherited Members
Extension Methods

Examples

// Define a strongly-typed ID
public class CustomerId : ScalarValueObject<Guid>
{
    private CustomerId(Guid value) : base(value) { }
    public static CustomerId NewUnique() => new(Guid.NewGuid());
}

// Define an entity
public class Customer : Entity<CustomerId>
{
    public string Name { get; private set; }
    public EmailAddress Email { get; private set; }
    public DateTime CreatedAt { get; }
    public DateTime? UpdatedAt { get; private set; }

    private Customer(CustomerId id, string name, EmailAddress email)
        : base(id)
    {
        Name = name;
        Email = email;
        CreatedAt = DateTime.UtcNow;
    }

    public static Result<Customer> TryCreate(string name, EmailAddress email) =>
        name.ToResult()
            .Ensure(n => !string.IsNullOrWhiteSpace(n), Error.Validation("Name required"))
            .Map(n => new Customer(CustomerId.NewUnique(), n, email));

    public Result<Customer> UpdateEmail(EmailAddress newEmail) =>
        newEmail.ToResult()
            .Tap(e =>
            {
                Email = e;
                UpdatedAt = DateTime.UtcNow;
            })
            .Map(_ => this);
}

// Usage - identity-based equality
var customer1 = Customer.TryCreate("John", email).Value;
var customer2 = Customer.TryCreate("John", email).Value;

// Different instances with same data but different IDs
customer1 != customer2; // true - different identities

// Same instance
var sameCustomer = customer1;
customer1 == sameCustomer; // true - same identity

Remarks

Entities are one of the three main building blocks in DDD (along with Value Objects and Aggregates). Key characteristics:

  • Identity: Each entity has a unique identifier that remains constant throughout its lifetime
  • Mutability: Entity state can change over time, but identity remains the same
  • Equality: Two entities are equal if they have the same ID, regardless of attribute values
  • Lifecycle: Entities have a continuous identity thread through state changes

Entities vs. Value Objects:

  • Entity: Defined by identity (e.g., Customer, Order, Product)
  • Value Object: Defined by attributes (e.g., Address, Money, EmailAddress)

Identity best practices:

  • Use strongly-typed IDs (e.g., CustomerId, OrderId) instead of primitives
  • Generate IDs at creation time, typically using NewUnique() or from external source
  • Make ID immutable using init-only setter
  • Never expose ID setters or allow ID changes after creation

Constructors

Entity(TId)

Initializes a new instance of the Entity<TId> class with the specified identifier.

protected Entity(TId id)

Parameters

id TId

The unique identifier for this entity. Must not be null or default.

Remarks

This constructor should be called by derived classes to set the entity's identity. The ID should typically be generated using a NewUnique() method or provided from an external source.

Properties

Id

Gets the unique identifier of this entity. The identifier is immutable and defines the entity's identity.

public TId Id { get; init; }

Property Value

TId

The unique identifier that distinguishes this entity from all others of the same type.

Remarks

The ID should be:

  • Set at construction time and never changed
  • Non-null and not equal to default(TId)
  • Unique within the entity type's scope
  • Preferably a strongly-typed value object (e.g., CustomerId, OrderId)

Methods

Equals(object?)

Determines whether the specified object is equal to the current entity. Two entities are equal if they have the same type and the same non-default ID.

public override bool Equals(object? obj)

Parameters

obj object

The object to compare with the current entity.

Returns

bool

true if the specified object is an entity of the same type with the same non-default ID; otherwise, false.

Remarks

This method implements identity-based equality, which is fundamental to entities in DDD. The method returns false if:

  • The compared object is not an entity of the same type
  • Either entity has a null or default ID (transient entities)
  • The IDs are different

Transient entities (those with null or default IDs) are never equal to other entities, even if they are the same instance. This prevents issues with unsaved entities.

GetHashCode()

Returns a hash code for this entity based on its type and ID.

public override int GetHashCode()

Returns

int

A hash code combining the entity type and its identifier.

Remarks

The hash code is based on both the entity type and its ID to ensure proper behavior in collections. Entities with the same ID but different types will have different hash codes.

Operators

operator ==(Entity<TId>?, Entity<TId>?)

Determines whether two entities are equal using identity-based comparison.

public static bool operator ==(Entity<TId>? a, Entity<TId>? b)

Parameters

a Entity<TId>

The first entity to compare.

b Entity<TId>

The second entity to compare.

Returns

bool

true if both entities are null, or if both have the same non-default ID; otherwise, false.

operator !=(Entity<TId>?, Entity<TId>?)

Determines whether two entities are not equal using identity-based comparison.

public static bool operator !=(Entity<TId>? a, Entity<TId>? b)

Parameters

a Entity<TId>

The first entity to compare.

b Entity<TId>

The second entity to compare.

Returns

bool

true if the entities have different IDs or one is null; otherwise, false.