Имам два сборни корена в моя домейн и следователно две хранилища. Ще ги наречем BookRepository и AuthorRepository, за пример.
Проектирам MVC приложение и една страница трябва да показва таблица, съдържаща списък с автори, като всеки ред показва личните данни на автора. В края на всеки ред има малък бутон, върху който може да се щракне, за да се разшири редът и да се покаже дъщерна таблица с подробности за публикуваните книги на автора.
Когато страницата се зареди, се изпълнява някакъв ajax, за да извлече подробностите за автора от API контролер и да покаже данните в таблицата. Всяко свойство в обект Author се преобразува почти директно в колона, с едно изключение и тук имам моя проблем. Искам бутонът в края на всеки ред да бъде деактивиран, ако и само ако авторът няма публикувани книги. Това означава, че с всеки запис на автор трябва да се върне булево значение, което показва дали има публикувани книги.
Моето хранилище за книги има няколко метода като този:
public IEnumerable<Book> GetBooksForAuthor(int authorId);
public bool AnyBooksForAuthor(int authorId);
и моят клас Book има свойство, наречено AuthorId, така че мога да извлека автора на книга чрез извикване
authorRepository.GetById(book.AuthorId);
Проблемът ми е, че за да създам ред за моята гореспомената таблица, трябва да го създам така:
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)
};
}
Кодът по-горе изглежда правилен, но има доста тежко наказание за производителност при извикването на this.bookRepository.AnyBooksForAuthor(author.Id) за всеки отделен автор, тъй като всеки път извършва извикване на база данни.
В идеалния случай предполагам, че бих искал AuthorTableRowRepository, който може да изпълнява нещо като следното:
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()
});
}
Колебая се да го поставя на място поради следните причини:
- AuthorTableRowRepository е хранилище на AuthorTableRows, но редът AuthorTable не е обект на домейн, нито обобщен корен и следователно не трябва да има свое собствено хранилище.
- Тъй като и авторът, и книгата са сборни корени, премахнах свойството „Книги“ от обекта автор, защото исках единственият начин за извличане на книги да бъде чрез BookRepository. Това прави HasBooks = a.Books.Any() невъзможно. Не съм сигурен обаче дали налагам собствената си заблудена най-добра практика тук. Изглежда погрешно да се получават книги чрез получаване на автор чрез AuthorRepository и след това преминаване през неговото свойство Books, и обратното при получаване на автор чрез свойство на обект Book. Предполагам, че пресичането на общите коренни граници би било начинът, по който бих го нарекъл?
Как други хора биха решили това? Притесненията ми неоснователни ли са? Най-вече съм загрижен за (какво трябва да бъде) постижение на производителността при първия метод, но искам да се придържам към най-добрите практики с модела на хранилището и DDD.