Skip to main content

Overview

Domain entities are the core building blocks of your domain model. They represent objects with unique identity and encapsulate business logic and validation rules.

Base Classes

DomainEntity

The foundational base class for all domain entities: DomainEntity<TKey, TValidator>. Located in Core.Domain.Entities.DomainEntity.
TKey
generic
The type of the entity’s unique identifier (e.g., string, Guid, int)
TValidator
generic
The validator type that implements IValidator and validates this entity

Properties

Id
TKey
The unique identifier for the entity. Has a protected setter to ensure identity immutability.
IsValid
bool
Gets whether the entity is valid according to its validator. Automatically triggers validation when accessed.
Validator
TValidator
The validator instance used to validate this entity.

Methods

GetErrors()
IList<ValidationFailure>
Returns a list of validation errors for the current entity state. Triggers validation before returning errors.
Validate()
void
Executes the validation logic using the entity’s validator. This method is called automatically by IsValid and GetErrors().

IValidate Interface

All domain entities implement the IValidate interface, which provides:
IsValid
bool
Property indicating if the entity passes all validation rules
GetErrors()
IList<ValidationFailure>
Method to retrieve all validation errors

Creating Custom Entities

Basic Entity Example

Here’s how to create a custom domain entity, based on DummyEntity from Domain/Entities/DummyEntity.cs:12:
using Core.Domain.Entities;
using Domain.Validators;
using static Domain.Enums.Enums;

namespace Domain.Entities
{
    public class DummyEntity : DomainEntity<string, DummyEntityValidator>
    {
        // Properties with private setters to enforce encapsulation
        public string DummyPropertyOne { get; private set; }
        public DummyValues DummyPropertyTwo { get; private set; }

        // Parameterless constructor for ORM/deserialization
        public DummyEntity()
        {
        }

        // Constructor for creating new entities
        public DummyEntity(string dummyPropertyOne, DummyValues dummyPropertyTwo)
        {
            Id = Guid.NewGuid().ToString();
            SetdummyPropertyOne(dummyPropertyOne);
            DummyPropertyTwo = dummyPropertyTwo;
        }

        // Constructor for reconstituting entities
        public DummyEntity(string dummyIdProperty, string dummyPropertyOne, DummyValues dummyPropertyTwo)
        {
            Id = dummyIdProperty;
            SetdummyPropertyOne(dummyPropertyOne);
            DummyPropertyTwo = dummyPropertyTwo;
        }

        // Behavior methods to modify state with validation
        public void SetdummyPropertyOne(string value)
        {
            DummyPropertyOne = value ?? throw new ArgumentNullException(nameof(value));
        }

        public void SetdummyPropertyTwo(DummyValues value)
        {
            DummyPropertyTwo = value;
        }
    }
}

Design Principles

Encapsulation

Entity properties should have private setters to prevent direct modification from outside the domain layer. This ensures that:
  • Business rules are always enforced
  • State changes go through validated methods
  • The Application layer cannot bypass domain logic
// ✅ Good: Private setter with public method
public string Name { get; private set; }

public void ChangeName(string newName)
{
    if (string.IsNullOrWhiteSpace(newName))
        throw new ArgumentException("Name cannot be empty");
    Name = newName;
}

// ❌ Bad: Public setter allows bypassing validation
public string Name { get; set; }

Identity Management

  • The Id property should be set in constructors
  • Use Guid.NewGuid() for new entities or accept an ID for existing entities
  • The ID should never change after creation (protected setter)

Validation

  • All entities are automatically validated through FluentValidation
  • Check IsValid property before persisting entities
  • Use GetErrors() to retrieve detailed validation messages
  • Validation occurs automatically when these properties/methods are called

Entity Examples

The architecture includes example entities in Domain/Entities/:
  • DummyEntity - Reference implementation showing all patterns

Best Practices

Use Value Objects

Extract complex properties into value objects for better encapsulation

Parameterless Constructor

Always provide a parameterless constructor for ORM frameworks and serialization

Factory Methods

Use static factory methods for complex entity creation logic

Domain Events

Raise domain events when important state changes occur

Build docs developers (and LLMs) love