这是一个真实的例子,它将引出我的问题:我有一个AddCommentToArticleCommand,它有一个ArticleId,评论文本和电子邮件地址。这个命令:
我应该像articleRepository.Save(文章)那样做吗?但是,如果只添加评论,为什么要保存文章呢?或者我可以做一些像articleRepository.SaveComment(评论),只会保存评论?或者你会采取什么方法?
谢谢!
答案 0 :(得分:8)
正如MattDavey指出的那样,在DDD中,您通常会考虑Aggregate生命周期,而不是CRUD持久性问题。 Aggregate的生命中期和结束时由相应的Repository处理。关于你的具体问题:
但现在我不知道保存添加的评论的最佳方法是什么?
处理此问题的最佳方法是找到可靠的ORM并实施
articles.MakePersistent(article)
使用此ORM的存储库方法。好的ORM将实现UnitOfWork,包括脏跟踪,延迟加载和其他与持久性相关的问题,而不会限制域对象。 ORM知道如何在保存聚合时避免不需要的SQL INSERT / UPDATE。您的域对象应尽可能持久无知。例如,NHibernate对您的对象施加的唯一约束是它们应该具有私有默认构造函数。除此之外,他们可以是简单的POCO对象,不知道所有持久性问题。要清除,域对象不应该有IsTransient
或IsDirty
标志。如果你发现自己编写使用这些标志的代码,那么你就是reinveting the wheel。
答案 1 :(得分:1)
在DDD中,通常情况下,您从聚合根中获取整个组合层次结构,并将其视为单个实体。所以,采用这种心态,“如果只添加评论,我为什么要保存文章?”,看起来整篇文章已经改变了,文章在数据库中的表现形式陈旧。理想情况下,您将替换数据库中的整个组合层次结构(使用文档数据库,这样会很好),但这可能会导致关系数据库中的性能问题。
在这种情况下,您可能决定让存储库扫描实体的组合,聚合root,并智能地决定如何处理每个组件。您可以使用访问者模式来遍历Comment对象,并根据它们是否是瞬态/脏,决定进行插入或更新,或者只是让它们单独使用..
我希望我已经足够清楚了,我不太擅长解释概念性事物:)
编辑:代码示例:
// 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);
}
}
}
}
}