Let's say we have an aggregate root entity of type Order that relates customers and order lines. When I think about an order entity it's more natural to conceptualize it as not being defined without an Id. An order without an Id seems to be better represented as an order request than an order.
To add an order to a repository, I usually see people instantiate the order without the Id and then have the repository complete the object:
class OrderRepository
{
void Add(Order order)
{
// Insert order into db and populate Id of new order
}
}
What I like about this approach is that you are adding an Order instance to an OrderRepository. That makes a lot of sense. However, the order instance does not have an Id, and at the scope of the consumer of the repository, it still makes no sense to me that an order does not have an Id. I could define an OrderRequest to be an instance of order and add that to the repository, but that feels like deriving an apple from an orange and then adding it to a list of oranges.
Alternatively, I have also seen this approach:
class OrderRepository
{
Order AddOrder(Customer customer)
// It might be better to call this CreateOrder
{
// Insert record into db and return a new instance of Order
}
}
What I like about this approach is that an order is undefined without an Id. The repository can create the database record and gather all the required fields before creating and returning an instance of an order. What smells here is the fact that you never actually add an instance of an order to the repository.
Either way works, so my question is: Do I have to live with one of these two interpretations, or is there a best practice to model the insertion?
EDIT: I just found this answer which is similar, but for value objects: http://stackoverflow.com/questions/566854/how-should-i-add-an-object-into-a-collection-maintained-by-aggregate-root. When it comes to a value object there is no confusion, but my question concerns an entity with identiy derived from an external source (Auto-Generated Database Id).