Say we have a generic repository with basic operations like Add(), Remove(), GetById()
This is OK if those members are not exposed outside the Data Access Layer. Basically, avoid generic repository. But, as this is not your core of the question, I will not go into the details of it here.
and we also have a specific repository per entity (e.g. ProductRepository, UserRepository, etc.)
This is good practice.
Should we define entity-related operations in the specific repositories or not? For example, in the ProductRepository, should I declare methods like GetProductsInCategory(), GetProductsByBrandId(), etc.
Those functions must be part of specific repository. In fact, that is the purpose of existence of specific repository.
or is this the responsibility of the service layer?
This is opinion based.
Yes; you drop the complete repository layer and do all that stuff in services.
No; abstract the database logic in repositories and keep your services database agnostic. Let them focus on business logic.
So the choice is yours.
The answer you linked suggests alternative to avoid creating too many filter methods in repository.
Instead it is better to have a query method on the repository which takes a Specification. You can pass different implementations of the Specification to retrieve the products.
Although I personally do not agree with it (it leaks data access components in calling layer as you have to accept Specification
instance from outside), it may be helpful where you have too much varying filter criteria.
Other point about that answer is that, apparently (that question is tagged as such), it is talking in terms of DDD. You have not mentioned DDD in your question.
In general, I do not agree with most of the claims that answer do; personally.
I'm really confused about the actual methods and operations that we have to implement in a repository.
Specific repositories should implement methods and operations that your calling layer need. If that layer need methods like GetProductsInCategory()
, GetProductsByBrandId()
, etc. you should implement those. As said above, this is the reason of existence of specific repositories.