est-ce une mauvaise pratique que le référentiel d'appels du contrôleur au lieu du service?
pour expliquer plus:
Je pense que dans une bonne conception, les contrôleurs appellent le service et le référentiel d'utilisation des services.
mais parfois dans le contrôleur, je n'ai/n'ai pas besoin de logique et j'ai juste besoin d'aller chercher dans db et de le passer pour le voir.
et je peux le faire en appelant simplement le référentiel - pas besoin d'appeler le service - est-ce une mauvaise pratique?
Non, pensez-y de cette façon: un référentiel est un service (aussi).
Si les entités que vous récupérez via le référentiel gèrent la majeure partie de la logique métier, il n'y a pas besoin d'autres services. Le simple fait d'avoir le dépôt suffit.
Même si vous disposez de certains services que vous devez passer pour manipuler vos entités. Saisissez d'abord l'entité dans le référentiel, puis transmettez-la audit service. Pouvoir lancer un HTTP 404 avant même d'essayer est très pratique.
De plus, pour les scénarios de lecture, il est courant que vous ayez juste besoin de l'entité pour le projeter sur un DTO/ViewModel. Le fait d'avoir une couche de service entre les deux entraîne souvent de nombreuses méthodes de transmission, ce qui est plutôt moche.
Ce n'est pas une mauvaise pratique pour un contrôleur d'appeler directement un référentiel. Un "service" n'est qu'un autre outil, alors utilisez-le là où cela a du sens.
NikolaiDante a commenté:
... Choisissez le bon modèle pour la bonne application. Je dirais que vous devez rendre votre candidature cohérente.
Je ne pense pas que la cohérence soit l'aspect le plus important. Une classe "service" est destinée à encapsuler une logique de niveau supérieur afin que le contrôleur n'ait pas besoin de l'implémenter. S'il n'y a pas de "logique de niveau supérieur" requise pour une opération donnée, allez directement dans le référentiel.
Pour promouvoir une bonne séparation des préoccupations et la testabilité, le référentiel doit être une dépendance que vous injectez dans le service via un constructeur:
IFooRepository repository = new FooRepository();
FooService service = new FooService(repository);
service.DoSomething(...);
Si la recherche d'enregistrements dans la base de données nécessite une sorte de requête paramétrée, une classe de service peut être un bon endroit pour prendre dans votre modèle de vue et créer une requête qui est ensuite exécutée par le référentiel.
De même, si vous avez un modèle de vue complexe pour un formulaire, une classe de service peut encapsuler la logique de création, de mise à jour et de suppression d'enregistrements en appelant des méthodes sur vos modèles/entités de domaine, puis en les conservant à l'aide d'un référentiel.
Dans la direction opposée, si votre contrôleur a besoin d'obtenir un enregistrement par son identifiant, déléguer à un objet de service pour cela revient à frapper une punaise avec un marteau - c'est bien plus que ce dont vous avez besoin.
J'ai trouvé que le contrôleur est le mieux placé pour gérer la transaction, ou un objet Unit Of Work . Le contrôleur ou l'objet Unit Of Work déléguerait alors des objets de service pour des opérations complexes, ou irait directement au référentiel pour des opérations simples (comme trouver un enregistrement par Id).
public class ShoppingCartsController : Controller
{
[HttpPost]
public ActionResult Edit(int id, ShoppingCartForm model)
{
// Controller initiates a database session and transaction
using (IStoreContext store = new StoreContext())
{
// Controller goes directly to a repository to find a record by Id
ShoppingCart cart = store.ShoppingCarts.Find(id);
// Controller creates the service, and passes the repository and/or
// the current transaction
ShoppingCartService service = new ShoppingCartService(store.ShoppingCarts);
if (cart == null)
return HttpNotFound();
if (ModelState.IsValid)
{
// Controller delegates to a service object to manipulate the
// Domain Model (ShoppingCart)
service.UpdateShoppingCart(model, cart);
// Controller decides to commit changes
store.SaveChanges();
return RedirectToAction("Index", "Home");
}
else
{
return View(model);
}
}
}
}
Je pense qu'un mélange de services et de travailler directement avec des référentiels est parfaitement acceptable. Vous pouvez encapsuler davantage la transaction dans un objet Unité de travail si vous en ressentez le besoin.
La répartition des responsabilités se présente comme suit:
Cela dépend de votre architecture. J'utilise Spring et la transactionnalité est toujours gérée par les services.
Si vous appelez des référentiels directement pour des opérations d'écriture (ou des services simples sans logique qui se contentent de déléguer au référentiel), vous utilisez probablement plusieurs transactions de base de données pour une opération qui doit être effectuée en une seule. Cela conduira à des données incohérentes dans votre base de données. En règle générale, les opérations de base de données doivent fonctionner ou échouer, mais les opérations à mi-travail sont la cause de maux de tête.
Pour cette raison, je pense que l'appel de référentiels directement à partir de contrôleurs, ou l'utilisation de services de délégation simples, est une mauvaise pratique. Vous commencez à le faire juste pour la lecture, et très bientôt vous, ou un de vos camarades, commencerez à le faire pour les opérations d'écriture.
Oui, c'est une mauvaise pratique. Le contrôleur ne doit être utilisé que pour contrôler le flux de votre application, obtenir des données des applications clientes, appeler le service et transmettre des données à la vue (JSON/HTML/XML/etc). Le référentiel/DAO doit être utilisé pour récupérer/conserver les données sans connaître la logique métier.
Envisagez les scénarios suivants: