Developers October 25, 2020

Repository Pattern Architecture

Alexandro Martinez @alexandromg

Hello, I’m struggling with architecture patterns.

Should my controllers or services commit changes to database?
I currently have:

Core:
-Entities:
--Invoice
--Ticket

Application
-Repositories:
—IInvoiceRepository
—ITicketRepository
-Services:
—IInvoiceService (gets invoices including their ticket)

Infrastructure:
-UnitOfWork (using DbContext and repositories as properties)
-Repository implementation
-Service implementation

Now for WebApi:

Option 1:
—InvoiceController.Delete:
var item = InvoiceService.GetAll()
InvoiceService.DeleteFull(item);
UoW.Commit();

Option 2:
—InvoiceController.Delete:
var item = InvoiceService.GetAll()
InvoiceService.DeleteFull(item); // inside calls UoW.Commit();

What do you think is the best practice when working with Unit of Work/Repository pattern?

  1. 4

    Im a big fan of services doing this kind of work, and letting the controllers stay small and just handle directing the request to the right service.

    1. 1

      So if a service handles business logic plus transactions (aka SaveChanges()) I need to have all my business logic on the service layer right? I also like the idea of Controller not implementing transactional behavior.

  2. 3

    You’re using dotnet core and entity framework?

    I don’t see the advantage of using the repository pattern and unit of work with ef. I did a project way back using both, and after writing a bunch of extra boilerplate came to the conclusion that it was effort wasted, and using the dbcontext directly in the service is the better solution. The only advantage of using the repository pattern with ef is in case you ever want to replace it with another orm, or write your own data access layer, and in all probability you won’t do either of those things. Just do controller and service.

    1. 1

      Yes, I thought so as well. But I've been following Mosh Hamedani's advice for years, since I believe he's a great teacher. You can see how he disputes your argument here, can you comment? It's on the 5:00-9:30 minute mark.

      1. 2

        His first argument is that you need the repository pattern to stop repeating the same query multiple times. You don’t. If you need to run the same query from multiple methods in your service, just have a private method in the service that does that query and call it from the public methods. It’s not exactly rocket science.

        He then invents the idea that returning IQueryable is a) a problem and b) a problem that should be solved by using the repository pattern. Neither of these things is true. You’re going to be calling .ToList() on everything leaving your service, or being further processed inside your service, so what does it matter? It’s an invented problem to make his argument look stronger.

        Then he says that not using the repository pattern tightly couples you to ef. This it does, but most likely you will never make the decision to stop using entity framework, which makes all the extra time and effort of setting up and maintaining repository and unit of work effort wasted.

        1. 1

          You’re right. I’ve seen this debate and 99% of devs argument this. Although my requirements need ODBC support, I cannot couple my application to EF in case I need to throw a Dapper command here and there. I need to use EF for a SaaS app but keep legacy code on Dapper/ODBC.

          1. 1

            Why do you need to use EF for a SaaS app, and Dapper for legacy?
            Last I checked, you can do a lot of the same things in both EF and Dapper.

            We chose Dapper for speed, but could have easily gone with EFCore instead (it's still slower than Dapper, but not as slow as EF6 was).

            1. 1

              Raw queries and commands that we'd need to rewrite in order to work with Informix db, specially regarding parameters. So we are using EF Core for new features and custom SQL for legacy implementation.

  3. 2

    Note that .NET Entity Framework already implements repository and unit of work patterns, so you can just create necessary models and use them directly.

  4. 2

    Ideally this is handled by the service layer. However you must be pragmatic. Nothing is cast in stone. Your biggest fear should not be getting the pattern or a specific implementation right, but rather over engineering. Remember the goal is simplicity..."maximise the work NOT done"......

  5. 1

    If someone is wondering I ended up injecting Unit of work inside Service implementations. Unit of work has a collection of repositories, and services can use other services as well. I didn’t like controllers performing transactions.

Recommended Posts