У меня есть два сводных корня в моем домене и, следовательно, два репозитория. Мы назовем их 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 не является ни объектом домена, ни корнем агрегата, и поэтому не должна иметь собственного репозитория.
- Поскольку Author и Book являются совокупными корнями, я удалил свойство «Книги» из сущности Author, потому что хотел, чтобы единственный способ получить книги — через BookRepository. Это делает HasBooks = a.Books.Any() невозможным. Я не уверен, навязываю ли я здесь свою ошибочную передовую практику. Кажется неправильным получать книги, получая Author через AuthorRepository, а затем просматривая его свойство Books, и наоборот, получая Author через свойство объекта Book. Полагаю, я бы назвал это пересечением совокупных корневых границ?
Как бы другие люди решили это? Мои опасения беспочвенны? Меня больше всего беспокоит (какой должна быть) производительность в первом методе, но я хочу придерживаться передовой практики с шаблоном репозитория и DDD.