0

J'ai deux racines agrégées dans mon domaine, et donc deux dépôts. Nous les appellerons BookRepository et AuthorRepository, à titre d'exemple.EF, Référentiels et frontières agrégées croisées

Je suis en train de concevoir une application MVC, et une page doit afficher une table contenant une liste d'auteurs, chaque ligne montrant les détails personnels de l'auteur. À la fin de chaque rangée est un petit bouton qui peut être cliqué pour agrandir la rangée et montrer une table d'enfant détaillant les livres publiés par l'auteur. Lorsque la page est chargée, une partie ajax est exécutée pour extraire les détails de l'auteur d'un contrôleur API et afficher les données dans la table

Chaque propriété d'un objet Auteur est mappée presque directement à une colonne, à une exception près, et c'est là que j'ai un problème. Je veux que le bouton à la fin de chaque ligne soit désactivé, si et seulement si l'auteur n'a pas de livres publiés. Cela signifie qu'un booléen doit être retourné avec chaque enregistrement d'auteur, indiquant s'ils ont des livres publiés.

Mon dépôt de livre a quelques méthodes comme ceci:

public IEnumerable<Book> GetBooksForAuthor(int authorId); 

public bool AnyBooksForAuthor(int authorId); 

et ma classe de livre a une propriété appelée AuthorID, donc je peux récupérer l'auteur d'un livre en appelant

authorRepository.GetById(book.AuthorId); 

Mon problème est que, afin de créer une rangée pour ma table ci-dessus, je dois le créer comme ceci:

IEnumerable<Author> authors = authorRepository.GetAll(); 
foreach (Author author in authors) 
{ 
    yield return new AuthorTableRow 
    { 
     Name = author.Name, 
     Age = author.Age, 
     Location = author.PlaceOfResidence.Name, 
     HasBooks = this.bookRepository.AnyBooksForAuthor(author.Id) 
    }; 
} 

Le code ci-dessus semble correct, mais il y a une pénalité de performance assez importante en appelant this.bookRepository.AnyBooksForAuthor (author.Id) pour chaque auteur, car il effectue un appel de base de données à chaque fois.

Idéalement, je suppose que je voudrais un AuthorTableRowRepository qui pourrait exécuter quelque chose comme ce qui suit:

public IEnumerable<AuthorTableRow> GetAll() 
{ 
    return from a in this.dbContext.Authors 
      select new AuthorTableRow 
      { 
       Name = a.Name, 
       Age = a.Age, 
       Location a.PlaceOfResidence.Name 
       HasBooks = a.Books.Any() 
      }); 
} 

Je hésite à mettre cela en place pour ces raisons:

  • AuthorTableRowRepository est un référentiel de AuthorTableRows, mais la ligne AuthorTable n'est pas un objet de domaine, ni une racine agrégée, et ne devrait donc pas avoir son propre référentiel. Comme Auteur et Livre sont tous deux des racines agrégées, j'ai supprimé la propriété "Livres" de l'entité Auteur, parce que je voulais que la seule façon de récupérer des livres soit via le BookRepository. Cela rend HasBooks = a.Books.Any() impossible. Je ne suis pas certain si j'impose ma propre meilleure pratique erronée ici. Il semble erroné d'obtenir des livres en obtenant un auteur via le dépôt AuthorRepository, puis en passant par sa propriété Books, et inversement en obtenant un auteur via une propriété sur un objet Book. Traverser les limites des racines agrégées serait la façon dont je l'appellerais, je suppose?

Comment les gens corrigeraient-ils cela? Mes inquiétudes sont-elles infondées? Je suis surtout préoccupé par la performance (ce qui devrait être) dans la première méthode, mais je veux adhérer à la meilleure pratique avec le modèle Repository et DDD.

+0

Pourquoi les downvotes ...? S'il vous plaît expliquer si je peux éviter des erreurs la prochaine fois? –

Répondre

0

La façon dont j'ai résolu cela à la fin était de créer une entité à partir d'une vue dans la base de données. J'ai nommé l'entité 'AuthorSummary' et créé un AuthorSummaryRepository qui ne contenait aucune méthode Add(), juste des méthodes de récupération.

0

Je maintiendrais la première approche, mais j'essayerais d'optimiser les choses dans la méthode bookrepository. Par exemple, vous pouvez charger cette information en une seule fois et utiliser la recherche en mémoire pour l'accélérer. Comme ceci vous auriez besoin de 2 requêtes, et non 1 pour chaque auteur.

+0

Comment la méthode bookrepository peut-elle être optimisée? C'est une question assez simple. Toute() requête à la base de données, je ne suis pas sûr de ce que je peux faire pour l'optimiser? –

+0

Eh bien, si le bookrepository avait une liste en mémoire pour le nombre de livres par auteur, il suffirait d'initialiser la liste avant la boucle, comme ceci; 'this.bookRepository.LoadBooksByAuthor(); IEnumerable authors = authorRepository.GetAll(); foreach (auteur de l'auteur dans les auteurs) {return new rendement AuthorTableRow { Name = author.Name, Âge = author.Age, Lieu = author.PlaceOfResidence.Name, HasBooks = this.bookRepository.AnyBooksForAuthor (auteur .Id) // cet appel ne va pas à la base de données, mais est juste une recherche en mémoire }; } ' –

+0

Est-ce vraiment mieux si le bookRepository a des millions de livres à charger? Le bookRepository ne peut pas non plus charger un sous-ensemble de la table, car il ne sait pas sur quels livres vous voulez obtenir des informations avant l'exécution de la requête d'auteur? –