What is the correct way to apply commands to objects deep within the model hierarchy?
Given the following model:
public class Picture : AggregateRoot
{
private string title;
private List<Shape> shapes;
}
public class Shape
{
private ShapeType Type;
private Color color;
}
We can define a CreatePicture command and PictureCreated event:
public class CreatePicture
{
Guid PictureId { get; set;}
string Title { get; set;}
}
public class PictureCreated
{
Guid PictureId { get; set;}
string Title { get; set;}
}
A simple implementation of the command handler might look like this:
var Picture = new Picture(cmd.PictureId, cmd.Title); // Internally store a PictureCreated event
repo.Add(Picture);
repo.Save(); // PictureCreated published
Then we can define an AddShape command and ShapeAdded event:
public class AddShape
{
Guid PictureId { get; set;}
ShapeType Type { get; set;}
}
public class ShapeAdded
{
Guid PictureId { get; set; }
Guid ShapeId { get; set;}
ShapeType Type {get; set; }
}
Again, the command handler looks like this:
var picture = repo.Get<Picture>(cmd.PictureId);
picture.AddShape(cmd.ShapeId, cmd.Title);
repo.Save(); // ShapeAdded published
But now, we define a ChangeShapeColor command and ShapeColorChanged event:
public class ChangeShapeColor
{
Guid PictureId { get; set; }
Guid ShapeId { get; set;}
Color Color { get; set;}
}
public class ShapeColorChanged
{
Guid PictureId { get; set; }
Guid ShapeId { get; set;}
Color Color { get; set;}
}
I'm not sure how the command handler should be implemented:
Option 1. All operations go via the Picture:
var picture = repo.Get<Picture>(cmd.PictureId);
picture.ChangeShapeColor(cmd.ShapeId, cmd.Color);
repo.Save(); // ShapeColorChanged published
Option 2. Operations go via the shape, which we look up from the Picture:
var picture = repo.Get<Picture>(cmd.PictureId);
var shape = Picture.GetShape(cmd.ShapeId);
shape.SetColor(cmd.Color);
repo.Save(); // ShapeColorChanged published
Option 1 doesn't seem too bad until we start building up a more complicated graph. e.g.
Building --(1..n)--> Floor --(1..n)--> Room --(1..n)--> Desk --(1..n)--> Equipment
It also seems like the aggregate root has turned in to a 'controller' (sorry if this is the wrong terminology) and is not an actualy domain object anymore.
What is the correct way to handle this? I can only find trivial/simple examples online where the model is practically flat.
Many thanks in advance.