Unterschied zwischen Repository und Service-Schicht?

In OOP Design Patterns, was ist der Unterschied zwischen dem Repository-Muster und einer Service-Schicht?

Ich arbeite an einer ASP.NET MVC 3 App und versuche diese Designmuster zu verstehen, aber mein Gehirn bekommt es einfach nicht … noch nicht !!

Der Repository-Layer bietet Ihnen eine zusätzliche Abstraktionsebene über den Datenzugriff. Anstatt zu schreiben

var context = new DatabaseContext(); return CreateObjectQuery().Where(t => t.ID == param).First(); 

Um ein einzelnes Element aus der database zu erhalten, verwenden Sie die Repository-Schnittstelle

 public interface IRepository { IQueryable List(); bool Create(T item); bool Delete(int id); T Get(int id); bool SaveChanges(); } 

und rufe Get(id) . Die Repository-Schicht legt grundlegende CRUD- Operationen offen .

Die Service-Schicht legt die Geschäftslogik offen, die das Repository verwendet. Beispieldienst könnte folgendermaßen aussehen:

 public interface IUserService { User GetByUserName(string userName); string GetUserNameByEmail(string email); bool EditBasicUserData(User user); User GetUserByID(int id); bool DeleteUser(int id); IQueryable ListUsers(); bool ChangePassword(string userName, string newPassword); bool SendPasswordReminder(string userName); bool RegisterNewUser(RegisterNewUserModel model); } 

Während die Methode List() des Repositorys alle Benutzer ListUsers() , kann ListUsers() von IUserService nur solche zurückgeben, auf die der Benutzer Zugriff hat.

In ASP.NET MVC + EF + SQL SERVER habe ich diesen Kommunikationsfluss:

Ansichten < - Controller -> Serviceebene -> Repository-Ebene -> EF -> SQL Server

Service-Schicht -> Repository-Schicht -> EF Dieser Teil arbeitet mit Modellen.

Ansichten < - Controller -> Serviceebene Dieser Teil arbeitet mit Ansichtsmodellen.

BEARBEITEN:

Beispiel für den Fluss für / Orders / ByClient / 5 (wir wollen die Bestellung für einen bestimmten Kunden sehen):

 public class OrderController { private IOrderService _orderService; public OrderController(IOrderService orderService) { _orderService = orderService; // injected by IOC container } public ActionResult ByClient(int id) { var model = _orderService.GetByClient(id); return View(model); } } 

Dies ist eine Schnittstelle für den Bestellservice:

 public interface IOrderService { OrdersByClientViewModel GetByClient(int id); } 

Diese Schnittstelle gibt das View-Modell zurück:

 public class OrdersByClientViewModel { CientViewModel Client { get; set; } //instead of ClientView, in simple project EF Client class could be used IEnumerable Orders { get; set; } } 

Dies ist eine Schnittstellenimplementierung. Es verwendet Modellklassen und ein Repository zum Erstellen eines Ansichtsmodells:

 public class OrderService : IOrderService { IRepository _clientRepository; public OrderService(IRepository clientRepository) { _clientRepository = clientRepository; //injected } public OrdersByClientViewModel GetByClient(int id) { return _clientRepository.Get(id).Select(c => new OrdersByClientViewModel { Cient = new ClientViewModel { ...init with values from c...} Orders = c.Orders.Select(o => new OrderViewModel { ...init with values from o...} } ); } } 

Wie Carnotaurus sagte, ist das Repository verantwortlich für die Zuordnung Ihrer Daten vom Speicherformat zu Ihren Geschäftsobjekten. Es sollte sowohl das Lesen als auch das Schreiben von Daten (Löschen, Aktualisieren) von und zum Speicher handhaben.

Der Zweck der Dienstschicht besteht andererseits darin, Geschäftslogik an einem einzigen Ort zu kapseln, um die Wiederverwendung von Codes und die Trennung von Problemen zu fördern. Was dies für mich in der Praxis beim Erstellen von Asp.net MVC-Sites bedeutet, ist, dass ich diese Struktur habe

[Controller] ruft [Service (s)] an, der [Repository (s)] aufruft]

Ein Prinzip, das ich als nützlich empfunden habe, ist die Minimierung der Logik in Controllern und Repositories.

Bei Controllern ist es, weil es mir hilft, DRY zu halten. Es ist sehr üblich, dass ich die gleiche Filterung oder Logik woanders verwenden muss und wenn ich es in den Controller setze, kann ich es nicht wiederverwenden.

In Repositories ist es, weil ich in der Lage sein möchte, meinen Speicher (oder ORM) zu ersetzen, wenn etwas besser kommt. Und wenn ich Logik im Repository habe, muss ich diese Logik neu schreiben, wenn ich das Repository ändere. Wenn mein Repository nur IQueryable zurückgibt und der Dienst die Filterung durchführt, muss ich nur die Zuordnungen ersetzen.

Zum Beispiel habe ich kürzlich mehrere meiner Linq-To-Sql-Repositories durch EF4 ersetzt, und diejenigen, bei denen ich diesem Prinzip treu geblieben bin, könnten innerhalb weniger Minuten ersetzt werden. Wo ich eine Logik hatte, war es nur eine Frage von Stunden.

Normalerweise wird ein Repository als Gerüst zum Befüllen Ihrer Entitäten verwendet – eine Service-Schicht würde ausgehen und eine Anfrage auslösen. Es ist wahrscheinlich, dass Sie ein Repository unter Ihre Service-Schicht stellen würden.

Die akzeptierte Antwort (und Hunderte von Zeit upvoted) hat einen großen Fehler. Ich wollte das in dem Kommentar darauf hinweisen, aber es wird einfach unten in 30 etwas beerdigt werden, was hier so aufzeigt.

Ich übernahm eine Unternehmensanwendung, die auf diese Weise erstellt wurde und meine erste Reaktion war WTH ? ViewModels in der Serviceebene? Ich wollte die Convention nicht ändern, weil Jahre der Entwicklung damit verbunden waren, also fuhr ich mit der Rückgabe von ViewModels fort. Junge, es wurde ein Albtraum, als wir anfingen, WPF zu benutzen. Wir (das Team von Entwicklern) haben immer gesagt: Welches ViewModel? Der echte (der, den wir für den WPF geschrieben haben) oder der Service? Sie wurden für eine Webanwendung geschrieben und hatten sogar das IsReadOnly- Flag, um die Bearbeitung in der Benutzeroberfläche zu deaktivieren. Major, Haupterrors und alles wegen eines Wortes: ViewModel !!

Bevor Sie den gleichen Fehler machen, sind hier noch einige weitere Gründe neben meiner obigen Geschichte:

Ein ViewModel aus der Service-Schicht zurückzugeben ist ein großes Nein. Das ist wie zu sagen:

  1. Wenn Sie diese Dienste verwenden möchten, verwenden Sie besser MVVM und hier ist das ViewModel, das Sie verwenden müssen. Autsch!

  2. Die Dienste machen die Annahme, dass sie irgendwo in einer UI angezeigt werden. Was ist, wenn es von einer Anwendung ohne Benutzeroberfläche wie Webdiensten oder Windows-Diensten verwendet wird?

  3. Das ist nicht einmal ein echtes ViewModel. Ein echtes ViewModel hat Beobachtbarkeit, Befehle usw. Das ist nur ein POCO mit einem schlechten Namen. (Siehe meine Geschichte oben, warum Namen wichtig sind.)

  4. Die konsumierende Anwendung sollte besser eine Präsentationsebene sein (ViewModels werden von dieser Ebene verwendet) und sie versteht C # besser. Ein weiterer Autsch!

Bitte, tu das nicht!