Where to put domain logic which needs to fetch data from database
I know that domain logic should be placed into domain objects. But what if my domain logic needs data from the database ? (e.g. checking unique value, computed values.. etc ) I think injecting repositories into my domain objects isn't the right thing. Also the service layer should not contain business rules开发者_如何学运维. So how to solve this kind of business logic ?
You are right your domain object should not read data directly from the database. The classic error here is that the domain object is sent over a web service and tries to read data from the database, when it is on a server without access to the database.
There are several ways to do this:
- a service layer preloads any information that the domain object will need
- the domain object can call a helper or repository that gets the data from the database
I have always found the service layer to be a logical place for invoking this type of activity - but as I will explain, that is not where it I implemented it, per se. Since the Service Layer is your gateway into the domain, you are assured that whatever request is initiating the need for this data, it will have to pass through this point to get there.
Additionally, having services talk to other services is very clean, as they are specifically designed to require a minimal effort to invoke. You can expose the adequate functionality you need in the repositories (i.e. a method / finder / query that could give you the count of X objects matching Y criteria) and wrap that in a handy service call. Not only does this give you more power to accomplish tasks easily in your within a single service, you can also then leverage this functionality between services for more complex requirements.
I understand the kind of concern around putting business logic in the service layer, but depending on the requirement, it is a fine line between what is business logic and what is implementation-specific business logic. In writing a system, there are often rules that surface that are implied as being business logic but just don't fit. Unique constraints are what I have found to be the most common example. Remember, just like everything else in the repository, this is not an implementation in the service layer, instead it is an abstraction of what is already in the domain.
What I do is place the "logic" itself in the domain, usually in the form of a specification pattern implementation. Since the logic is executed in the repository and does not require that the service layer be changed, I have come to terms with this being completely acceptable. You will find that rules that apply to collections of entities are usually the "fun" ones. If you only need to verify that something is unique with a collection within the aggregate root, it is simple enough to do.
I have seen approaches where the domain object has knowledge of the repository, and I am just personally not a fan. The repository, to me, is the definition of how the domain will interface with the persistence layer (although not always the implementation). The fact that an entity even has knowledge that it has a greater purpose than to just exist complicates matters immensely.
精彩评论