Skip to main content

Entities vs Value Objects: Identity Matters

TL;DR

ConceptEntityValue Object
IdentityHas unique IDDefined by attributes
EqualitySame ID = sameSame attributes = equal
MutabilityCan changeImmutable
ExamplesCustomer, OrderMoney, Address

The Core Distinction

Entities: Identity Matters

var customer1 = new Customer(id: "C001", name: "John Smith");
var customer2 = new Customer(id: "C002", name: "John Smith");
customer1.Equals(customer2); // FALSE - different IDs

Value Objects: Attributes Matter

var money1 = new Money(100, Currency.USD);
var money2 = new Money(100, Currency.USD);
money1.Equals(money2); // TRUE - same value

Implementation

Value Object (C# record)

public record Money(decimal Amount, Currency Currency)
{
public Money Add(Money other)
{
if (Currency != other.Currency)
throw new CurrencyMismatchException();
return new Money(Amount + other.Amount, Currency);
}
}

public record Address(string Street, string City, string PostalCode);

public record EmailAddress
{
public string Value { get; }
public EmailAddress(string value)
{
if (!IsValidEmail(value))
throw new ArgumentException("Invalid email");
Value = value.ToLowerInvariant();
}
}

Strongly-Typed IDs

public record CustomerId(Guid Value)
{
public static CustomerId New() => new(Guid.NewGuid());
}

public record OrderId(Guid Value);

// Now type-safe - can't mix them up
public Order GetOrder(OrderId id) { ... }

Common Mistakes

// ❌ Primitive obsession
public class Customer
{
public string Email { get; set; } // Any string
public decimal Balance { get; set; } // What currency?
}

// ✅ Value Objects
public class Customer
{
public EmailAddress Email { get; private set; }
public Money Balance { get; private set; }
}

// ❌ Mutable Value Object
public class Money { public decimal Amount { get; set; } }

// ✅ Immutable Value Object
public record Money(decimal Amount, Currency Currency);

Decision Guide

  1. Track over time? → Entity
  2. Interchangeable with same value? → Value Object
  3. Has lifecycle? → Entity
  4. Immutability natural? → Value Object

When in doubt: Start with Value Object (easier to change VO → Entity).