2017-02-23 1 views
1

Je les référentiels suivants:Référentiels conception confusion

  • EmployeeRepository
  • DocumentRepository
  • CourseRepository
  • LeaveRepository

Nous avons une exigence maintenant d'ajouter un nouvel objet métier appelé BusinessTripBidding qui permet à l'employé s d'enchérir pour différents voyages d'affaires et ainsi. Quoi qu'il en soit, le problème est lorsque vous renvoyez la liste de Bidders J'ai besoin d'inclure des informations de tous les dépôts mentionnés ci-dessus que l'entreprise exige, puis je génère un nouvel objet et retourne une liste (dans mon objet métier), quelque chose comme:

IEnumerable<BidderInfo> GetBiddersInfo(int tripId) 
{ 
    List<Bidder> bidders = _bidderRepository.GetListByTripId(tripId); 

    List<Course> courses = _courseRepository 
     .GetListByEmployeeId(bidders.Select(b => b.EmployeeId).AsEnumerable()); 

    List<Document> passports = _documentRepository 
     .GetListByEmployeeId(bidders.Select(b => b.EmployeeId).AsEnumerable(), DocumentType.Passport); 

    List<Leave> leaves = ........... 

    var biddersInfo = new List<BidderInfo>(); 
    foreach(Bidder b in bidders) 
    { 
     var bi = new BidderInfo(); 
     bi.Courses = courses.Where(c => c.EmployeeId == b.EmployeeId).ToList(); 
     bi.Passport = passports.FirstOrDefault(p => p.EmployeeId == b.EmployeeId); 

     bi.ComingLeave = ......... 

     // the same for the rest of the repositories 

     biddersInfo.Add(bi); 
    } 
    return biddersInfo; 
} 

a côté des multiples appels à la db, et à côté de la boucle, il serait beaucoup plus facile si je crée un nouveau référentiel seul responsable pour créer cette BidderInfo en une seule requête, nous allons l'appeler BidderInfoGeneratorRepository puis injecter ce dépôt dans le constructeur de l'objet métier. Maintenant, devrais-je garder les choses comme je le fais actuellement (plusieurs appels db) mais les choses semblent correctes; ou devrais-je créer un autre référentiel et le transmettre à l'objet métier pour accélérer les choses? Quelle est la meilleure pratique dans ce cas?

Répondre

1

La meilleure pratique dépend de la quantité et de la vitesse de modification des données. Si vos données ne sont que de quelques centaines/milliers de lignes et changent lentement, vous pouvez les mettre en cache dans l'application et invalider le cache lors des mises à jour. Lorsque vos données sont trop volumineuses pour les stocker dans la mémoire, j'évite autant que possible les appels multiples sans une forte augmentation de la complexité du code.

+0

'sans une forte augmentation de la complexité du code' c'est la question ... comment? Mon approche est-elle correcte en créant un nouveau référentiel à cette fin? – Him

+0

Dans ce cas, vous pouvez créer un nouveau référentiel. Deux petites choses: vous filtrez vos parcours deux fois quand je le vois correctement. Deuxièmement: je n'appellerais pas ToList() sur la définition de bi.Courses, car elle diminue la performance. – Dexion

+0

Le premier filtre est d'obtenir la liste des cours pour tous les employés dans cette demande, le GetByEmployeeId a une surcharge qui accepte 'IEnumerable '. Le deuxième filtre est d'obtenir l'employé spécifique. – Him

1

J'éviterais le couplage étroit entre les dépôts.

Bien que je suis un grand fan de premier domaine agnosticisme de données, et d'autres bonnes pratiques à mettre en œuvre des architectures à base de DDD, je dirais que vous pouvez toujours conserver ces fonctions pendant que vous n'avez pas besoin de coupler vos dépôts de cette façon.

BTW, si je comprends bien votre approche, je trouve qu'il ya un défaut de conception dans votre raisonnement: BidderInfo est un objet de domaine , mais ce n'est pas un objet persistant, non? Les référentiels sont conçus pour fonctionner avec la couche de mappage de données afin de conserver les changements de domaine et de fournir des requêtes agnostiques. Ma première conclusion en lisant votre code est que toute la méthode devrait aller dans un service de domaine où vous pouvez injecter autant de dépôts que vous le souhaitez car c'est le bon endroit pour le faire.

Deuxièmement, il y a quelque chose qui pourrait simplifier encore plus les choses et c'est peut-être votre solution définitive: pourquoi ne pas transformer BidderInfo en objet persistant?

Je ne devrais pas deviner à tort si je pense que vous utilisez un OR/M, non?Par conséquent, si vous le configurez de la bonne façon, vous pouvez persister BidderInfo et l'obtenir automatiquement dans une seule requête (ou qui sait, mais ce sera un rôle d'optimisation OR/M). Par conséquent, vous allez créer l'ensemble BidderInfoRepository sur lequel vous allez simplement implémenter un GetById(...) qui appellera l'OR/M dans les coulisses.

Sinon, vous devez placer ce code dans la couche de service .

+0

Votre conclusion est correcte, l'idée est venue car il y a un bon gain de performance, je pensais qu'il est même permis de mettre une partie de la logique dans une procédure stockée si cela vous donnera un bon gain de performance. objet qui ne peut pas être enregistré directement dans la base de données, il obtient ses propriétés à partir de nombreuses autres tables, comme indiqué. Considérez cela comme un genre de rapport .. confus ici :) – Him

+0

@Him Hey;) Lire [cet article] (https://martinfowler.com/bliki/CQRS.html) composé par Martin Fowler. Après l'avoir déjà lu, nous pouvons continuer la discussion! –

+0

vous m'avez fait lire au sujet de CQRS pour l'heure passée maintenant. C'est un système vraiment cool mais il est impossible pour l'instant de refactoriser un vieux projet. Merci pour les conseils cependant :) – Him