Extension methods to the rescue (from repository)

Extension methods to the rescue (from repository)

In one of my previous posts (which you can read here), I’ve told about my feelings for the repository pattern. Complaining about something is one thing (please, don’t even try to tell me, that you have never seen some piece of code, that made you cry like a baby), however, if we want to (pretend to) be professionalists, it is very important to come up with some ideas in order to solve the given problem (at least partially). In this post, I’ll present to you one of my solutions to the commonly misused repository pattern (especially on the querying side).


 

Disclaimer – in case you have never heard of the extension methods, please read the following article on the MSDN. On top of that, you may find many useful (like hundreds of them) examples here.

Let’s get to work, and see how we can use the extension methods to act as a querying part of the repository pattern. I’ll provide the examples for both MSSQL and MongoDB databases using the popular Entity Framework and MongoDB Driver  respectively, but keep in mind that presented techniques are universal and should be a good fit pretty much everywhere.

At first, I’ll define the core classes that will be used for both examples (on a side note, I’m not going to use any common patterns such as IoC to keep that code as simple as possible). So, ladies and gentlemen, here it comes, the legendary User entity, along with the IUserService that can act as an application service:

Please do note that whether the IUserService should return the domain entities (probably not and it could return DTO instead) is not important in this example. What truly matters is that this piece of code is responsible for performing some critical operations, such as creating a new user or finding another one for a given email address. Now, let’s take a look at the common, generic example of the repository pattern:

And how it could be used within the IUserService:

May I present to you another one, much better, specialized version of the UserRepository?

And its usage within the IUserService:

If you truly want to use the repository, please use the latter implementation. At that point you may actually stop reading that post (but I do encourage you not to). Otherwise, if you want to find out how to make use of the extension methods please stay with me. Let’s begin with the Entity Framework implementation first.

And here we go:

Which boils down to the following usage in the IUserService:

And pretty much the same for the MongoDB Driver:

That we can use like that:

What have we gained? At least the following:

  • We got rid of the one layer (which simplifies the overall project structure).
  • Querying methods (but feel free to implement the remaining CRUD operations if you feel a strong need for that) can be easily used within all of the application services (no more “injection” of the many repositories interfaces).
  • Since we are aware about the underlying data storage that is being used, we may compose extension methods queries e.g. by returning an IQueryable interface. It’s quite easy to build a custom, fluent interface for the data access layer. Moreover, we can take the advantage of that knowledge to maximize the application performance.

Maybe we can not easily swap the data storage anymore but hold on for a second… could we really do that before?

P.S.
You may download the full example here.

6 Comments Extension methods to the rescue (from repository)

  1. Pingback: dotnetomaniak.pl

    1. Piotr Gankiewicz

      I think that extension methods have as many opponents and supporters as e.g. “var” keyword.
      I do get your point, and surely it may be used in a wrong way, but personally I find this to be a rather useful tool that helps with a fluent API design or defining a “clean” helper methods.
      As for the testing in the above example, I don’t really find too many issues. You can easily test it, just need to be aware that e.g. with the integration testing, it’s not as obvious as with “mocking” the repository methods. Instead, you need to mock the database itself, which is pretty straightforward for example with Effort library if EF is being used.

      Reply
    1. Piotr Gankiewicz

      Yes, I am, it was meant to be a very trivial example :). The only method that is not typical for the repository is CreateAsync(), as it takes some input parameters, and internally creates a domain object, which is saved into the database (infrastructure).
      Thanks for the link, I do know this approach, both the Query and Command handlers, and have been using it for quite some time. Actually, I was planning, to write a post about that someday in the future :).

      Reply
  2. pb

    Jak to w końcu jest z tym wzorcem Repozytorium + ORM?
    Czytałem wiele publikacji na ten temat i co człowiek to opinia.
    Część osób twierdzi, że tworzenie repozytorium i korzystanie z ORM-a to niepotrzebne tworzenie abstrakcji nad abstrakcją, z kolei inna grupa programistów uważa, że ułatwia to podmianę źródła danych(z czym w sumie się zgadzam).

    Jak to wygląda w Twoich projektach?
    Z tego co widziałem w Twoich kursach, rekomendujesz użycie repozytoriów, aczkolwiek w kursach mamy do czynienia tylko z danymi przechowywanymi w pamięci.

    Jak to wygląda w momencie kiedy źródłem danych jest relacyjna baza danych i korzystasz z EF?

    Czy repozytorium powinno być dla każdej encji?
    Co w takim razie kiedy potrzebujemy zrobić join-y z innych tabel?

    Reply

Leave a Reply to Piotr Gankiewicz Cancel reply

Your email address will not be published. Required fields are marked *