Можно ли, чтобы репозиторий DDD работал со сводными объектами в дополнение к реальным объектам?

Скажем, я создаю репозиторий для хранения цифровых электронных книг, как показано в интерфейсе ниже. В этом репозитории будет храниться фактический текст книги, а также метаданные, идентифицирующие книгу (название, автор, издатель, ISBN и т. д.).

public interface IBookRepository
{
    void AddBook(Book newBook);
    void DeleteBook(int bookId);
    void UpdateBook(Book updatedBook);
    Book GetBook(int bookID)
} 

public class Book
{
    public int BookId {get; set;}
    public string Title {get; set;}
    public string Author {get; set;}
    public IList<Page> Contents {get; set}
}

public class Page
{
    public int PageNumber {get; set;}
    public string PageContent {get; set;}
}

В большинстве случаев я не хотел бы получать весь текст книги, так как это было бы довольно дорого. В большинстве случаев меня интересуют только метаданные, например, я могу просто создать список книг. Итак, было бы приемлемо в отношении DDD также разрешить IBookRepository иметь методы, которые возвращают BookSummary объекты? Объекты сводки книги будут включать метаданные, но не фактическое содержание книги.

Как насчет метода UpdateBook(BookSummary book)? Скажем, я хочу обновить свойство Book.Rating, но мне не нужно/не хочется читать все содержимое книги из репозитория, чтобы сделать это.

public interface IBookRepository
{
    //Full Book Methods
    void AddBook(Book newBook);
    void DeleteBook(int bookId);
    void UpdateBook(Book updatedBook);
    Book GetBook(int bookID)

    //BookSummary Methods
    BookSummary GetBookSummary(int bookID)
    IEnumerable<BookSummary> GetBooksByAuthor(string authorName);
    IEnumerable<BookSummary> GetBooksByGenre(int genreId);
    void UpdateBook(BookSummary bookSummary);
} 


public class BookSummary
{
    public int BookId {get; set;}
    public string Title {get; set;}
    public string Author {get; set;}
    public int PageCount {get; set;}
}

Примечание. Я знаю, что использование ORM с отложенной загрузкой также было бы решением этой проблемы, но я хотел бы проектировать свои репозитории без предположения, что будет использоваться отложенная загрузка


person Eric Anastas    schedule 09.06.2011    source источник


Ответы (3)


Если в вашем домене есть вариант использования, который его поддерживает, почему бы просто не создать дополнительный объект BookSummary с собственным репозиторием, который будет выполнять эту работу? На самом деле не имеет значения, где хранится BookSummary — это не имеет отношения к Домену.

Важно вывести Сущности из Домена, используя вездесущий язык, а не смотреть на структуру базы данных.

public interface IBookRepository
{
    //Full Book Methods
    void Add(Book Book);
    void Delete(Book Book);
    Book findById(int bookID)
}

public interface IBookSummaryRepository
{
    //Full Book Summary Methods
    void Add(BookSummary BookSum);
    void Delete(BookSummary BookSum);
    Book findById(int bookSummaryID)
}

Если в вашем репозитории есть методы update() или store(), это скорее DAO, чем репозиторий с помощью DDD: http://codebetter.com/iancooper/2011/04/12/repository-saveupdate-is-a-smell/

person Tomas Dermisek    schedule 10.06.2011
comment
Да, но мой домен ожидает найти BookSummary, если книга будет добавлена ​​в IBookRespository. Если это отдельные репозитории, то невозможно гарантировать, что добавление книги в один приведет к тому, что BookSummary появится в другом. Конечно, вы можете настроить два репозитория, указывающих на одну и ту же таблицу базы данных, но это будет конкретная реализация. Для меня наличие одного репозитория означает, что все данные, поступающие из репозитория, поступают из одного и того же хранилища данных. См. мой последний вопрос SO, связанный с этим: bit.ly/jjUhbi - person Eric Anastas; 10.06.2011
comment
Вы можете вызвать один репозиторий из другого. - person Vijay Patel; 10.06.2011
comment
Я думал, что репозитории не должны вызывать другие репозитории: stackoverflow.com/questions/1364461/, - person Eric Anastas; 11.06.2011

В репозитории DDD должен работать только с совокупным корнем. В вашем случае, я полагаю, BookSummary — это просто объект внутри агрегата Book (конечно, здесь нужен более точный анализ), поэтому следует получить Book через BookRepository, а затем перейти к BookSummary из корня агрегата, используя отложенную загрузку. В противном случае вы не применяете здесь проект, управляемый доменом.

person xelibrion    schedule 10.06.2011
comment
Я добавил код для BookSummary. Я не думаю, что BookSummary является сущностью внутри агрегата Book. BookSummary имеет тот же идентификатор, что и соответствующая книга. Он представляет то же самое, только в другой форме. Это просто уменьшенная/прокси-версия книги. Я понимаю, что использование ORM с отложенной загрузкой устранит необходимость в типе BookSummary. Тем не менее проектирование репозитория с предположением, что будет использоваться отложенная загрузка, не кажется более правильным, чем проектирование репозитория с предположением, что будет использоваться SQL Server. Интерфейс должен быть независимым от реализации. - person Eric Anastas; 10.06.2011
comment
Я бы посоветовал вам не иметь BookSummary. Вот несколько вариантов, как это сделать: 1. Загрузить только те данные, которые необходимы (используя ленивые свойства или проекции) 2. Ввести отдельное хранилище, оптимизированное для чтения (применить здесь принципы CQRS) 3. Разделить книгу на книгу и книгу (здесь нет дублирующихся данные, как в текущей модели). В любом случае, если вы не вводите хранилище для чтения, вам придется загружать ВЕСЬ агрегат (используя ленивую загрузку или нет). Если вы этого не сделаете, вы скатитесь к подходу, основанному на данных. - person xelibrion; 10.06.2011

Это старый вопрос, однако на него нет принятого ответа, поэтому я отвечу на благо людей, прибывающих сюда из Google. Я постоянно сталкиваюсь с этой проблемой, так как у нас есть много сводных экранов, которые показывают частичную информацию и/или информацию, собранную из нескольких объектов. Я использую отдельные модели чтения, предложенные @xelibrion в комментариях к его ответу. Я не использую полный CQRS, только простые модели чтения только с методами запроса. Итак, ваш BookRepository остается таким:

public interface IBookRepository
{
    void AddBook(Book newBook);
    void DeleteBook(int bookId);
    void UpdateBook(Book updatedBook);
    Book GetBook(int bookID)
}

И ваша модель чтения BookSummary и ее методы выглядят так:

public class BookSummary
{
    public int BookId {get; set;}
    public string Title {get; set;}
    public string Author {get; set;}
    public int PageCount {get; set;}
} 

public interface IBookSummaryQueries
{
    BookSummary GetBookSummary(int bookID)
    IEnumerable<BookSummary> GetBooksByAuthor(string authorName);
    IEnumerable<BookSummary> GetBooksByGenre(int genreId);
}

Обратите внимание, что здесь нет способов обновить Книгу, только запрос

person Louise Eggleton    schedule 19.05.2016