I have an AR and I can't figure out the best way to create/edit some of the complex aggregates contained in it. These aggregates have many parameters so I decided within the domain model to use Value Objects instead of primitive types.
public class Load : AggregateRoot
{
public virtual string Name { get; protected set; }
public virtual User ResponsibilityOf { get; protected set; }
public virtual User AssignedTo { get; protected set; }
public virtual User CoveredBy { get; protected set; }
public virtual State State { get; protected set; }
public virtual Cargo Cargo { get; protected set; }
public virtual Guid CustomerId { get; protected set; }
public virtual IList<Run> Runs { get; protected set; }
public Load(Guid customerId, string name) : this()
{
if (string.IsNullOrEmpty(name))
throw new ArgumentNullException(nameof(name));
Name = name;
CustomerId = customerId;
Runs = new List<Run>();
}
}
Runs is a collection of Value Objects and Run is defined below. It's a good example of the issue I'm facing because it takes several parameters and some of them are Value Objects.
public sealed class Run : ValueObject<Run>
{
public int Order { get; private set; }
public Location Origin { get; private set; }
public Location Destination { get; private set; }
public Guid CarrierId { get; private set; }
private Run() { }
public Run(Guid carrierId, Location origin, Location destination, int order = 0) : this()
{
if (carrierId == Guid.Empty)
throw new ArgumentNullException(nameof(carrierId));
Origin = origin ?? throw new ArgumentNullException(nameof(origin));
Destination = destination ?? throw new ArgumentNullException(nameof(destination));
Order = order;
CarrierId = carrierId;
}
}
I want to add methods for CRUD operations for Runs to the AR (Load) and I don't know how to approach it. This would be a trivial task if Origin and Destination were primitives or they only took one or two parameters to instantiate. But Origin and Destination are Value Objects.
public sealed class Location: ValueObject<Location>
{
public string Name { get; private set; }
public Address Address { get;private set; }
public string Notes { get; private set; }
public string Directions { get; private set; }
public int CustomerId { get; private set; }
public string HoursOfOperation { get; private set; }
public Phone Phone { get; private set; }
}
So when I go to add my CRUD methods to the Aggregate Root Load, I'm lost on how best to achieve this goal. I could add the following, but it doesn't seem like the DDD way to solve this problem because outside of the domain should not know what Run is right?
void AddRun(Run run);
void RemoveRun(Run run);
void UpdateRun(Guid id, Run run );
If outside of the domain doesn't know what Run is, I would have to use primitive types as parameters and that would get messy really fast because there would need to be so many parameters to build up the object.
Edit 1: Corrected a few things pointed out in answers.