The purpose of a Service Layer is to provide a layer of abstraction between your persistence layer (CRUD operations) and your presentation layer.
Given this, it is not surprising that you're finding books that say it is not a good idea for your presentation layer to interact with your repository objects directly. The whole point of the Service Layer is to shield you from having to interact directly with the database; doing so would bypass the very abstraction you seek.
If you're providing a Service Layer between your client (the presentation layer) and your database (i.e. the repository), you should be exposing methods in your Service Layer that provide services, not CRUD operations. Effectively, you can think of your Service Layer as a translator between CRUD operations and business practices.
For example, your Service Layer might expose a method called CreateInvoice()
. To do that, this service method would have to look up Customer
, Invoice Header
, Invoice Line Item
, Product
and Pricing
entities from your repository. It does all of this via CRUD operations. But you won't get all of those entities as a return value; rather, you're more likely to get some sort of composite ViewModel
object that contains a view of all of the data required to render the invoice.
So no, you wouldn't simply pass-through your CRUD calls to the Service Layer API. Doing so is indeed redundant, and would defeat the whole purpose of having a service layer.
Further Reading
P of EAA Catalog | Service Layer