Сохранение сущностей домена
вот реальный пример, который приведет к моему вопросу: у меня есть 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);
}
}
}
}
}