# Domain-Driven Design - Detailed Reference
Detailed code examples cho DDD patterns trong GoodGo.
## Table of Contents
1. [Entity Patterns](#entity-patterns)
2. [Value Objects](#value-objects)
3. [Aggregates](#aggregates)
4. [Domain Events](#domain-events)
5. [Domain Services](#domain-services)
6. [Specifications](#specifications)
---
## Entity Patterns
### Complete Entity Base Class
```csharp
///
/// EN: Base Entity class with domain events support.
/// VI: Base Entity class với hỗ trợ domain events.
///
public abstract class Entity : IEquatable
{
private readonly List _domainEvents = new();
private int? _requestedHashCode;
public virtual Guid Id { get; protected set; }
public IReadOnlyCollection DomainEvents => _domainEvents.AsReadOnly();
protected void AddDomainEvent(IDomainEvent domainEvent)
{
_domainEvents.Add(domainEvent);
}
public void ClearDomainEvents() => _domainEvents.Clear();
public bool IsTransient() => Id == default;
public bool Equals(Entity? other)
{
if (other is null) return false;
if (ReferenceEquals(this, other)) return true;
if (GetType() != other.GetType()) return false;
if (IsTransient() || other.IsTransient()) return false;
return Id.Equals(other.Id);
}
public override bool Equals(object? obj) => Equals(obj as Entity);
public override int GetHashCode()
{
if (IsTransient()) return base.GetHashCode();
_requestedHashCode ??= Id.GetHashCode() ^ 31;
return _requestedHashCode.Value;
}
public static bool operator ==(Entity? left, Entity? right) => Equals(left, right);
public static bool operator !=(Entity? left, Entity? right) => !Equals(left, right);
}
```
### Child Entity (OrderItem)
```csharp
///
/// EN: OrderItem entity belonging to Order aggregate.
/// VI: Entity OrderItem thuộc Order aggregate.
///
public class OrderItem : Entity
{
public Guid ProductId { get; private set; }
public string ProductName { get; private set; }
public int Quantity { get; private set; }
public decimal UnitPrice { get; private set; }
public decimal TotalPrice => Quantity * UnitPrice;
// EN: Required by EF Core
private OrderItem() { }
internal OrderItem(Guid productId, string productName, int quantity, decimal unitPrice)
{
Id = Guid.NewGuid();
ProductId = productId;
ProductName = productName ?? throw new ArgumentNullException(nameof(productName));
SetQuantity(quantity);
UnitPrice = unitPrice >= 0 ? unitPrice
: throw new ArgumentException("Price cannot be negative");
}
internal void SetQuantity(int quantity)
{
if (quantity <= 0)
throw new DomainException("Quantity must be positive");
Quantity = quantity;
}
internal void IncreaseQuantity(int amount)
{
if (amount <= 0)
throw new ArgumentException("Amount must be positive");
Quantity += amount;
}
}
```
---
## Value Objects
### Value Object Base
```csharp
///
/// EN: Base class for value objects with equality support.
/// VI: Base class cho value objects với hỗ trợ equality.
///
public abstract class ValueObject : IEquatable
{
protected abstract IEnumerable