Question

I've been reading a lot on the role of the repository pattern and the service layer and I'm (I think) well aware of the distinction between the two. But a simple problem has me scratching my head for some time now.

I know how the data access layer is responsible for well... accessing the data so a typical repository might have methods like insert, update, delete, and save (the basic CRUD methods). The service layer contains all the business stuff, validation, sending email and all that jazz and one thing I read was that the service layer should not repeat repository methods since this setup doesn't add any value.

But my problem is with the 'add' method. Let's say I have a supplier class and I want to add a specific supplier to my suppliers list. The user enters the supplier information through the UI (MVC web app) and the Create controller method gets called.

Now what should the controller deal with in order to persist this supplier?

  • The repository directly
  • The service layer

Since a pure repository implementation won't do anything else than persist the entity, if I have some validation and / or business rule I should use the service layer obviously. But if I don't should the controller deal directly with the repository? It seems to me as if this breaks the layered nature of the architecture. The controller is skipping the service layer and talking to the persistence layer.

Let's say I want to be on the safe side and use the service layer (since I might have validation and other stuff related to dealing with suppliers). I'll end up with:

  • an AddSupplier method
  • an UpdateSupplier method
  • a DeleteSupplier method

which is what I didn't want in the first place since now I have a 1 to 1 method mapping with the service layer and the data access layer.

So my question to you is: Where does the (Add | Update | Delete)Supplier methods should go?

Also, is it OK to bypass the service layer and talk directly to the repository layer from the controller?

Was it helpful?

Solution

I don't think there is one definitive answer to your question as there are many factors to consider (it's also a bit of a paradox as you've pointed out). I believe the best implementation has a few important pieces.

  1. An extremely generic repository, which interacts with the data source and performs the insert, update, delete basic CRUD methods (as you've pointed out). Optimally this would be done in a generic way so your interaction is consistent across your app. For example a method that returns a single entity like T Single(Func<T, bool> where).

  2. Specific business services that contain methods which encapsulate business functions. These services are the only ones allowed to interact with the Repository. Beyond 'Hello World' style examples, these methods would not simply add or remove an item, but they might interact with 2 or more entities and perform complex business logic. For example a service method may be 'CreateAccount' or 'RemmoveBlogPost', which undoubtedly would require more than simply adding a single entity or removing one.

  3. 'Thin' and 'Dumb' controllers which perform virtually no logic but merely call service methods as needed. Controllers simply consume variables and return responses. However, they may call a variety of service methods in each controller action. The mixing and reusing of service methods results in efficient and DRY coding practices.

This methodology shows its strength when you realize that you want to perform all or part of some method in another part of your app. For example if you were building a blogging app, you might find that the public facing side of the app needs a way to view a single blog post and the admin side needs it as well. In this simple example, returning a blog post by Id would be repeated in each controller, however, if you created one service method called getBlogPostById, you could reuse the logic in both controllers.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top