I apologize in advance if folks think this has been beaten to death. I've just spent the last few hours searching and reading many excellent posts here in SO but I'm still confused.
The source of my confusion is DTO vs. DDD and repositories. I want my POCO domain objects to have the smarts, and I want to get them from repositories. But it seems like I have to violate some encapsulation rules to make that work, and it seems like it can turn DTO's onto their heads.
Here's a simple example: In our catalog application, a Part could be a package that includes a number of other parts. So, it makes sense for the Part POCO to have a 'GetChildren()' method which returns IEnumerable< Part >. It might even do other stuff with the list on its way out.
But how is that list resolved? Seems like the repository is the answer:
interface IPartRepository : IRepository<Part>
{
// Part LoadByID(int id); comes from IRepository<Part>
IEnumerable<Part> GetChildren(Part part);
}
And
class Part
{
...
public IEnumerable<Part> GetChildren()
{
// Might manipulate this list on the way out!
return partRepository.GetChildren(this);
}
}
So now the consumers of my catalog, in addition to (correctly) loading parts from the repository, can also bypass some Part-encapsulated logic by calling GetChildren(part) directly. Isn't that bad?
I read that repositories should serve up POCO's but that DTO's are good for transferring data 'between layers.' A lot of part properties are computed - prices, for example, are calculated based on complex pricing rules. A price won't even be in a DTO coming from a repository - so it seems like passing pricing data back to a web service requires the DTO to consume the Part, not the other way around.
This is already getting too long. Where is my head unscrewed?
Repository interface belongs to the domain layer since it plays the roles of defining the operations on Entity required for implementing business logic (Service).
Yes, repository implementations can definitely be a part of your domain model.
Yes, a domain service can access repositories.
Repository pattern separates the data access logic and maps it to the business entities in the business logic. Communication between the data access logic and the business logic is done through interfaces. To put it simply, Repository pattern is a kind of container where data access logic is stored.
One approach that solves this problem is to move the logic into the child parts themselves - that is, change the semantics of the class so that Part
objects are responsible for transforming themselves when they are associated with a parent.
For example, if the price of a Part
is dependent on its parent Part
, the price can be determined at the following times (at a minimum):
Upon construction, if a parent Part
(and all other necessary data) is available.
In an AttachToParent(Part parentPart)
method or in response to an event, i.e., OnAttachedToParent(Part parentPart)
.
When it is needed by client code (i.e., on the first access of its Price
property).
Edit: my original answer (below) really wasn't in the spirit of DDD. It involved making domain objects simple containers, a design considered by many to be an anti-pattern (see Anemic Domain Model).
An additional layer between the Part
and IPartRepository
(I'll call it IPartService
) solves this problem: move GetChildren(part)
into IPartService
and remove it from Part
, then make client code call IPartService
to get Part
objects and their children rather than hitting the repository directly. The Part
class still has a ChildParts
(or Children
) property - it just doesn't know how to populate it itself.
Obviously, this imposes additional costs - you may end up writing or generating a lot of pass-through code for repository calls if you don't need extra business logic in most cases.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With