web-dev-qa-db-fra.com

Différence entre le référentiel et la couche de service?

Dans OOP Modèles de conception, quelle est la différence entre le modèle de référentiel et un calque de service?)

Je travaille sur une application ASP.NET MVC 3 et j'essaie de comprendre ces modèles de conception, mais mon cerveau ne comprend tout simplement pas ... encore !!

178
Sam

La couche de référentiel vous offre un niveau supplémentaire d'abstraction par rapport à l'accès aux données. Au lieu d'écrire

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

pour obtenir un seul élément de la base de données, vous utilisez l'interface de référentiel

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

et appelez Get(id). La couche de référentiel expose les opérations de base CRUD .

La couche de service expose la logique métier, qui utilise le référentiel. Exemple de service pourrait ressembler à:

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);
}

Bien que la méthode List() du référentiel renvoie tous les utilisateurs, ListUsers() de IUserService ne peut en renvoyer que des utilisateurs auxquels l'utilisateur a accès.

Dans ASP.NET MVC + EF + SQL SERVER, j'ai ce flux de communication:

Vues <- Contrôleurs -> Couche de service -> Couche de référentiel -> EF -> SQL Server

Couche de service -> Couche de référentiel -> EF Cette partie fonctionne sur des modèles.

Vues <- Contrôleurs -> Couche de service Cette partie fonctionne sur les modèles de vues.

EDIT:

Exemple de flux pour/Orders/ByClient/5 (nous voulons voir la commande pour un client spécifique):

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); 
    }
}

C'est l'interface pour le service des commandes:

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

Cette interface retourne le modèle de vue:

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

Ceci est la mise en œuvre de l'interface. Il utilise des classes de modèle et un référentiel pour créer un modèle de vue:

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

Comme le dit Carnotaurus, le référentiel est chargé de mapper vos données du format de stockage sur vos objets métier. Il devrait gérer à la fois comment lire et écrire des données (supprimer, mettre à jour aussi) depuis et vers le stockage.

D'autre part, l'objectif de la couche de service est d'encapsuler la logique métier en un seul endroit afin de promouvoir la réutilisation du code et la séparation des problèmes. Ce que cela signifie généralement pour moi lors de la création de sites Asp.net MVC, c’est que j’ai cette structure.

[Contrôleur] appelle [Service (s)] qui appelle [référentiel (s)]

Un principe que j’ai trouvé utile est de limiter au maximum la logique dans les contrôleurs et les référentiels.

Dans les contrôleurs, c'est parce que cela m'aide à rester au sec. Il est très courant que je doive utiliser le même filtrage ou la même logique ailleurs et si je le place dans le contrôleur, je ne peux pas le réutiliser.

Dans les référentiels, c'est parce que je veux pouvoir remplacer mon stockage (ou ORM) lorsque quelque chose de mieux se présente. Et si j'ai une logique dans le référentiel, j'ai besoin de la réécrire lorsque je change de référentiel. Si mon référentiel ne retourne que IQueryable et que le service effectue le filtrage, il me suffira de remplacer les mappages.

Par exemple, j'ai récemment remplacé plusieurs de mes référentiels Linq-To-Sql par EF4 et ceux où je suis resté fidèle à ce principe pourraient être remplacés en quelques minutes. Là où j’avais une certaine logique, c’était plutôt une question d’heures.

38
Mikael Eliasson

La réponse acceptée (et multipliée par des centaines de fois) présente un défaut majeur. Je voulais le signaler dans le commentaire, mais il sera simplement enterré dans 30 commentaires, alors rappelez-le.

J'ai repris une application d'entreprise construite de cette manière et ma réaction initiale a été [~ # ~] avec [~ # ~] ? ViewModels dans la couche de service? Je ne voulais pas changer la convention car des années de développement s'étaient écoulées et j'ai donc continué à retourner ViewModels. Il s'est transformé en cauchemar lorsque nous avons commencé à utiliser WPF. Nous (l'équipe de développeurs) disions toujours: quel ViewModel? Le vrai (celui que nous avons écrit pour le WPF) ou celui des services? Ils ont été écrits pour une application Web et avaient même le drapeau IsReadOnly pour désactiver l'édition dans l'interface utilisateur. Majeur, défaut majeur et tout à cause d'un mot: ViewModel !!

Avant de commettre la même erreur, voici quelques raisons supplémentaires en plus de mon histoire ci-dessus:

Renvoyer un ViewModel à partir de la couche service est un énorme no no. C'est comme dire:

  1. Si vous souhaitez utiliser ces services, vous feriez mieux d'utiliser MVVM et voici le ViewModel que vous devez utiliser. Ouch!

  2. Les services supposent qu'ils seront affichés quelque part dans une interface utilisateur. Que se passe-t-il s'il est utilisé par une application autre qu'une interface utilisateur telle que des services Web ou des services Windows?

  3. Ce n'est même pas un véritable ViewModel. Un vrai ViewModel a une observabilité, des commandes, etc. C'est juste un POCO avec un mauvais nom. (Voir mon histoire ci-dessus pour savoir pourquoi les noms comptent.)

  4. L’application consommatrice doit être une couche de présentation (les modèles ViewModels sont utilisés par cette couche) et comprendre mieux le C #. Un autre Ouch!

S'il vous plaît, ne faites pas ça!

16
CodingYoshi

Généralement, un référentiel est utilisé comme échafaudage pour renseigner vos entités. Une couche de service sort et source une requête. Il est probable que vous placeriez un référentiel sous votre couche de service.

7
CarneyCode

La couche de référentiel est implémentée pour accéder à la base de données et permet d'étendre les opérations CRUD sur la base de données. Tandis qu’une couche de service se compose de la logique d’application de l’application et peut utiliser la couche de référentiel pour mettre en œuvre une certaine logique impliquant la base de données. Dans une application, il est préférable d’avoir une couche de référentiel et une couche de service distinctes. La séparation des couches de référentiel et de service rend le code plus modulaire et dissocie la base de données de la logique métier.

3
Akshay