Сохранение сущностей домена

вот реальный пример, который приведет к моему вопросу: у меня есть AddCommentToArticleCommand, у которого есть ArticleId, текст комментария и адрес электронной почты. Эта команда:

  • использует репозиторий статьи для получения статьи (которая является объектом домена)
  • Если статья существует, она вызывает article.AddComment(commentText, emailAddress), который добавляет комментарий к статье и выдает исключение, когда он не может (из-за неправильного формата электронной почты, статьи были закрыты, комментарий не заполнен или слишком длинный и т.д.)
  • но теперь я не знаю, что лучший способ сохранить добавленный комментарий?

Должен ли я делать что-то вроде articleRepository.Save(статья)? Но почему, почему я должен сохранить статью, если был добавлен только комментарий? Или я могу сделать что-то вроде articleRepository.SaveComment(комментарий), который сохранит комментарий? Или какой подход вы бы взяли здесь?

Спасибо!

Ответ 1

Как MattDavey указывает, что в DDD вы обычно думаете о Агрегировать жизнь а не о проблемах с сохранением CRUD. Середина и конец жизни Агрегата обрабатывается соответствующим репозиторием . Что касается вашего конкретного вопроса:

но теперь я не знаю, что лучший способ сохранить добавленный комментарий?

Лучший способ справиться с этим - найти надежную ORM и реализовать

articles.MakePersistent(article)

используя этот ORM. Хорошая ORM реализует UnitOfWork, будет включать в себя грязное отслеживание, ленивую загрузку и другие проблемы, связанные с сохранением, без ограничения ваших объектов домена. ORM знает, как избежать необходимости SQL INSERT/UPDATE при сохранении агрегата. Объекты вашего домена должны быть как можно более неустойчивыми. Единственное ограничение, которое NHibernate, например, ставит на ваши объекты, состоит в том, что у них должен быть собственный конструктор по умолчанию. Кроме того, они могут быть простыми объектами POCO, не осознающими всех проблем с сохранением. Для очистки объектов домена не должны иметь флаги IsTransient или IsDirty. И если вы обнаружите, что пишете код, который использует эти флаги, вы реконструируете колесо.

Ответ 2

В DDD часто бывает, что вы берете всю иерархию композиций из совокупного корня и рассматриваете ее как единый объект. Итак, приняв этот менталитет, "почему я должен сохранить статью, если был добавлен только комментарий?", Казалось бы, что статья в целом изменилась, а представление статьи в базе данных устарело. В идеале вы заменили бы всю иерархию композиций в базе данных (с базой документов это было бы хорошо), однако это может привести к проблемам с производительностью в реляционной БД.

В этом случае вы можете решить, что сканирование репозитория над составом сущности, заполнить корень вниз и разумно решить, что делать с каждым компонентом. Вы можете использовать шаблон посетителя для итерации объектов Comment, и в зависимости от того, являются ли они временными/грязными, решите сделать вставку или обновление или просто оставить их в покое.

Надеюсь, я был достаточно ясен, я не очень хорошо объясняю концептуальные вещи:)

EDIT: Пример кода:

// In ArticleRepository...
public void Save(Article article)
{
    // IsTransient (as opposed to IsPersistant) means "has not yet been saved"...
    if (article.IsTransient)
    {
        DB.InsertArticle(article);
        // Inserting the article also inserts any comments / sub components...
    }
    else
    {
        // IsDirty means "has been modified since it was taken from the DB"...
        if (article.IsDirty)
        {
            DB.UpdateArticle(article);
        }

        foreach(var comment in article.Comments)
        {
            if(comment.IsTransient)
            {
                DB.InsertComment(article.Id, comment);
            }
            else
            {
                if (comment.IsDirty)
                {
                    DB.UpdateComment(comment);
                }
            }
        }
    }
}