.NET Core — Using the Specification pattern alongside a generic Repository

Rodrigo Santos
6 min readOct 11, 2019

Link to the same article on my blog here.

In this post we are going to show how the Specification pattern can be used alongside a generic Repository using .NET Core.

An example application will be used, and it will be the same as used in this other post I made.

If you wish to get the starting source code and code as you read here is the link for: GitHub.

There is no silver bullet when we structure an application but using this combination of patterns, can make our code modular and with great reusability and DRY (Don’t Repeat Yourself).

The Repository and Unit Of Work pattern

The Repository and Unit of Work pattern are intended to create an abstraction layer between the business logic layer and the data access layer of an application.

From the book “Patterns of Enterprise Application Architecture”, by Martin Fowler, the Repository “mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects” while the Unit Of Work “maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems”.

Regarding the usage of these patterns in .NET Core, there is some discussion between developers if they are useful or not. There are the arguments (there are more but these are the ones I considered the most):

For:

  • All database related code is in one place;
  • It is easier to mock and test, since mocking a repository is easier than mocking a DbSet;
  • It ensures the separation of concerns principle;
  • The application is not tightly coupled to any ORM we use (EF Core in this case). If we want to change to another ORM, we can make it without needing to make any change to the interface of the data access layer;
  • It is clear which operations are allowed for specific entities (can also be considered an against argument, depending on the requirements and implementation of the application);

Against:

  • Repository/Unit Of Work pattern just duplicates what Entity Framework Core gives us with a DbContext — an abstraction from the database;
  • If you consider a repository for each one of your entities, inheriting from a generic repository, with time, your code will get huge;

The Specification pattern

The Specification pattern allows us to encapsulate some piece of domain knowledge into a single unit (the specification) and reuse it in different parts of the code base.

It provides us a good solution to the problem of where to place the querying, sorting and paging logic since it describes a query in an object.

For:

  • A specification has a name that we can reason about;
  • It can be unit tested in isolation (a bunch of LINQ expressions cannot);
  • It can be easily reused;
  • Can be used to describe the shape of the data to be returned — the queries can return just the data they required, eliminating the need for lazy loading in web applications;

Why and how we should mix them?

In a large application with many domain objects and many possible queries, the Repository pattern reduces the amount of code needed to deal with all the querying that is needed. Adding to this, a generic Repository promotes the Specification pattern, which encapsulates the query to be performed in a pure object-oriented way. We can simply write code purely in terms of object and put SQL in the background.

For example, to encapsulate a paged query that searches for recipes and need to include the users that have made such recipes, we can create a SearchRecipesWithUsers specification which would take any parameters we need and have the overloads — allow a class to have more than one method having the same name, if their argument lists are different — we wish. The generic Repository would have a method that receives a specification as an argument and would be able to return the expected result according to the provided specification.

Having these two patterns together helps keeping repository implementations from becoming cluttered with such specific details when querying.

Setting up the Specification

To start with some coding, if you want to follow, the source code to start is the same we ended in this post (Github).

On our business logic layer (BL), let’s create an interface for any specification that can be made.

To use the operations defined in the interface, let’s also create an abstract class that implements these operations, on our data access layer (DAL).

This is the set of operations that a specification can do. If you wish to add more, feel free to do it but for the scope of this post, these should be enough.

Adding to this, we are also going to make another class in order to apply the specifications that a user defines to an IQueryable. This is the point where we will make the Repository and Specification pattern work together.

Adding the Repository and the Unit Of Work

Now that we have our specification in place with its operations, we can add the repository with the needed operations.

Keep in mind that our Find method receives the specification in order to make the query we wish. Let’s see how it works.

Whenever we use a specification to make a query, we call the GetQuery static method from the SpecificationEvaluator we defined before.

Although it is not recommended to return IQueryable from a repository, it is fine to use them within the repository to build up a set of results. It can be used to build up the query we need before executing it with the specification criteria.

Now that we have the Repository and the Specification patterns in place, let’s add the Unit Of Work.

We will use just generic repositories and will not need to define a repository for each object in case we have specific queries for each one of them. Why? Because such queries will be specified using the Specification pattern as an argument of the Find method of the Repository, as we have seen before. With this approach we follow the DRY principle and achieve a very modular way of making queries using specifications, since each query we would need will be implemented in an object-oriented way.

Let’s make such query. We want to return a user or list of users with his recipes and ingredients as an example. Currently, with just the operations of our repository, we can’t achieve that. We create a new class with such requirements.

All specifications will inherit from the BaseSpecification class we defined early and add the criteria we need. In this case, making use of the AddInclude method, both for a list of users and for a user with a specific id.

Wiring it up with the Controllers

To finish our post, we need to wire all this logic with the Controllers. Right now, the controller uses the DbContext directly but since now we have the Unit of Work and Repository pattern in place, we can encapsulate all database related code in one place.

Conclusion

And there you have it. Using the Specification pattern with the Unit Of Work/Repository pattern provides us with a very modular code, keeping our code organized and making it easy to add more complexity as the application grows.

As said, there is no silver bullet when coding or architecting an application, but I consider this approach as a good practice.

Link to the same article on my blog here.

Source code: GitHub

Support Us

Our organization is a non-profit organization. However, we have many expenses across our activity. From infrastructure to service expenses, we need some money, as well as help, to support our team and projects. For the expenses, we created several channels that will mitigate this problem. First of all, you can support us by being one of our Patreons. Second, you can support us on Open Collective page. Thirdly, you can buy one coffee (or more) for us. Fourth, you can also support us on our Liberapay page. Last but not least, you can directly support us on PayPal. On the other hand, we also need help in the development of our projects. Therefore, if you have the knowledge we welcome you to support our projects. Just follow our channels and repositories.

--

--

Rodrigo Santos

Full-Stack developer with a great passion to learn. NET Core enthusiast. More about me in https://www.rodrigo-santos.me