Strategy for updating huge entity's collection that belongs to Aggregate Root

330 Views Asked by At

I'm stuck with a specific scenario regarding Aggregates and not breaking business invariants.

I've two entities, let's call them Order and OrderItem. Both entities belong to an aggregate with Order as Aggregate root.

When I need to update one specific OrderItem I do it through the Aggregate root:

class Order
{
    private Collection $orderItems;

    public function __construct()
    {
        $this->orderItems = new Collection;
    }

    public function updateOrderItemPrice(OrderItemId $id, int $newPrice): void
    {
        foreach ($this->orderItems as $orderItem) {
            if ($orderItem->id()->equals($id) {
                $orderItem->updatePrice($newPrice);
                break;
            }
        }  
    }
}

While this solution works fine for small collections, it can lead to a huge performance penalty when we're talking about thousands (or tens of thousands) of records due the ORM (Doctrine in my case) will try to load all the order items in memory when you're about to iterate it.

Is there any pattern or good practice to solve this specific scenario?

1

There are 1 best solutions below

1
Alex Khonko On
class OrderItemId {
    public function __construct(private readonly int $value)
    {
    }

    public function getValue(): int
    {
        return $this->value;
    }
}

class OrderItem {
    
    public function __construct(private readonly OrderItemId $id)
    {
    }

    public function getId(): OrderItemId
    {
        return $this->id;
    }
}

class OrderItemCollection {
    private array $items = [];
    
    private function add(OrderItem $item): void {
        $this->items[$item->getId()->getValue()] = $item;
    }
    
    public function has(OrderItemId $id): bool
    {
        return array_key_exists($id->getValue(),$this->items);
    }
    
    public function get(OrderItemId $id): OrderItem
    {
        return $this->items[$id->getValue()];
    }
}

class Order
{
    private OrderItemCollection $orderItems;

    public function __construct()
    {
        $this->orderItems = new OrderItemCollection;
    }

    public function updateOrderItemPrice(OrderItemId $id, int $newPrice): void
    {
        if($this->orderItems->has($id))
        {
            $this->orderItems->get($id)->updatePrice($newPrice);
        }
    }
}