Entities vs Value Objects: Identity Matters
TL;DR
| Concept | Entity | Value Object |
|---|---|---|
| Identity | Has unique ID | Defined by attributes |
| Equality | Same ID = same | Same attributes = equal |
| Mutability | Can change | Immutable |
| Examples | Customer, Order | Money, 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
- Track over time? → Entity
- Interchangeable with same value? → Value Object
- Has lifecycle? → Entity
- Immutability natural? → Value Object
When in doubt: Start with Value Object (easier to change VO → Entity).