You've got value objects representing your business logic, containing business rules. Now you are adding a mechanism to persist them. Fair enough. How about you add a mechanism to read a database and construct them from it? Perhaps a static Load
method taking IGetMyEntity
instance as a parameter?
While you are at it, maybe it is the best to add a few more methods:
RenderAsHtml
,ToString
,ToJson
,ToXml
.
You see where I am going with this? It all starts with a simple Save
method, but a few commits later your objects suddenly know everything, have low cohesion, everything is crammed up in a single place and impossible to reuse without dragging the rest of the unwanted boilerplate with it.
The repository pattern became very popular because it scales well. If the object you are talking about is really supposed to be an in-memory representation of a business rule, it is NOT okay to include CRUD methods as a part of its API.
To expand on your opinion about DTOs, when you are doing some operation, where do you generally need a validation of business rules? Is it on reads? Most likely not. You may prohibit access to some resource, but it's more of an authorization issue rather than a business rule.
The place where you are likely to enforce business rules is when data comes into your system (be it completely new or coming through an update). On that occasion you need to check the operation altering state of your system is valid, ie. may be performed. For this you should use value objects or entities enforcing the constraints. Repository really is not a place to contain business logic. The goal of a repository is to abstract persistence of objects, not to enforce business rules. The objects passed to the repository MUST make sure they are valid themselves before being passed to a repository for further processing.
Also it is better not to look at a repository as a class knowing all CRUD operations, but rather like a layer within your application. When your application grows it's likely you are going to need multiple representation of an entity on reads. Should you have a repository as a single class having multiple Get*
methods does not feel right and the class could become quite big and difficult to maintain soon - coming from a personal experience.