wake-up-neo.com

Unterschied zwischen Repository und Service Layer?

Was ist in OOP Design Patterns der Unterschied zwischen dem Repository Pattern und einem Service Layer?

Ich arbeite an einer ASP.NET MVC 3-App und versuche, diese Entwurfsmuster zu verstehen, aber mein Gehirn versteht es einfach nicht ... bis jetzt !!

178
Sam

Die Repository-Ebene bietet Ihnen eine zusätzliche Abstraktionsebene für den Datenzugriff. Anstatt zu schreiben

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

um ein einzelnes Element aus der Datenbank abzurufen, verwenden Sie die Repository-Schnittstelle

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

und rufe Get(id) auf. Die Repository-Ebene macht grundlegende ROHE Operationen verfügbar.

Die Serviceschicht legt die Geschäftslogik offen, die das Repository verwendet. Beispielservice könnte so 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<User> ListUsers();
    bool ChangePassword(string userName, string newPassword);
    bool SendPasswordReminder(string userName);
    bool RegisterNewUser(RegisterNewUserModel model);
}

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

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

Ansichten <- Controller -> Service-Schicht -> Repository-Schicht -> EF -> SQL Server

Serviceschicht -> Repository-Schicht -> EF Dieser Teil funktioniert auf Modellen.

Views <- Controllers -> Service Layer Dieser Teil funktioniert auf View-Modellen.

EDIT:

Beispiel für den Ablauf für/Orders/ByClient/5 (wir möchten die Reihenfolge 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 die Schnittstelle für den Bestellservice:

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

Diese Schnittstelle gibt das Ansichtsmodell zurück:

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

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

public class OrderService : IOrderService
{
     IRepository<Client> _clientRepository;
     public OrderService(IRepository<Client> 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...}     
             }
         );
     }
}
308
LukLed

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

Auf der anderen Seite besteht der Zweck der Service-Schicht darin, die Geschäftslogik an einem einzigen Ort zusammenzufassen, um die Wiederverwendung von Code und die Trennung von Bedenken zu fördern. Für mich bedeutet dies in der Praxis beim Erstellen von Asp.net MVC-Sites normalerweise, dass ich über diese Struktur verfüge

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

Ein Prinzip, das ich für nützlich befunden habe, besteht darin, die Logik in Controllern und Repositorys auf ein Minimum zu beschränken.

In Controllern liegt es daran, dass es mir hilft, mich trocken zu halten. Es kommt sehr häufig vor, dass ich dieselbe Filterung oder Logik an einer anderen Stelle verwenden muss, und wenn ich sie in den Controller stecke, kann ich sie nicht wiederverwenden.

In Repositories liegt es daran, dass ich meinen Speicher (oder ORM) ersetzen möchte, wenn sich etwas Besseres ergibt. 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 ausführt, muss ich nur die Zuordnungen ersetzen.

Zum Beispiel habe ich kürzlich mehrere meiner Linq-To-Sql-Repositorys durch EF4 ersetzt, und diejenigen, bei denen ich diesem Prinzip treu geblieben war, konnten innerhalb von Minuten ersetzt werden. Wo ich Logik hatte, waren es stattdessen Stunden.

38
Mikael Eliasson

Die akzeptierte Antwort (und Hunderte von Stimmen) hat einen großen Fehler. Ich wollte dies im Kommentar verdeutlichen, aber es wird nur in 30 Kommentaren vergraben, die hier darauf hinweisen.

Ich habe eine Unternehmensanwendung übernommen, die auf diese Weise erstellt wurde, und meine erste Reaktion war [~ # ~] mit [~ # ~] ? ViewModels in der Serviceebene? Ich wollte die Konvention nicht ändern, da sie jahrelang weiterentwickelt wurde, also fuhr ich mit der Rücksendung von ViewModels fort. Junge, es wurde ein Albtraum, als wir anfingen, WPF zu verwenden. Wir (das Entwicklerteam) haben immer gesagt: Welches ViewModel? Die echte (die, die wir für das WPF geschrieben haben) oder die Dienste? Sie wurden für eine Webanwendung geschrieben und hatten sogar das IsReadOnly-Flag , um die Bearbeitung in der Benutzeroberfläche zu deaktivieren. Schwerwiegender, schwerwiegender Fehler und alles wegen eines Wortes: ViewModel !!

Bevor Sie den gleichen Fehler machen, hier sind einige weitere Gründe zusätzlich zu meiner obigen Geschichte:

Das Zurückgeben eines ViewModel aus der Service-Schicht ist ein großes Nein Nein. Das ist wie zu sagen:

  1. Wenn Sie diese Dienste nutzen möchten, sollten Sie MVVM verwenden. Hier ist das ViewModel, das Sie verwenden müssen. Autsch!

  2. Die Dienste gehen davon aus, dass sie irgendwo in einer Benutzeroberfläche angezeigt werden. Was ist, wenn es von einer Nicht-UI-Anwendung wie Webdiensten oder Windows-Diensten verwendet wird?

  3. Das ist nicht mal 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 aufwändige Anwendung sollte eine Präsentationsebene sein (ViewModels werden von dieser Ebene verwendet) und C # besser verstehen. Noch ein Autsch!

Bitte, tu das nicht!

16
CodingYoshi

Normalerweise wird ein Repository als Gerüst verwendet, um Ihre Entitäten zu bevölkern - eine Service-Schicht geht aus und sendet eine Anfrage. Es ist wahrscheinlich, dass Sie ein Repository unter Ihre Serviceschicht stellen.

7
CarneyCode

Die Repository-Ebene wird für den Zugriff auf die Datenbank implementiert und hilft bei der Erweiterung der CRUD-Operationen für die Datenbank. Während eine Service-Schicht aus der Geschäftslogik der Anwendung besteht und die Repository-Schicht verwenden kann, um bestimmte Logik zu implementieren, die die Datenbank einbezieht. In einer Anwendung ist es besser, eine separate Repository-Schicht und eine separate Service-Schicht zu haben. Durch getrennte Repository- und Service-Schichten wird der Code modularer und die Datenbank von der Geschäftslogik entkoppelt.

3
Akshay