保存域实体更改

时间:2011-09-21 07:29:30

标签: c# domain-driven-design repository entity cqrs

这是一个真实的例子,它将引出我的问题:我有一个AddCommentToArticleCommand,它有一个ArticleId,评论文本和电子邮件地址。这个命令:

  • 使用文章存储库来获取文章(域实体)
  • 如果文章存在,则会调用article.AddComment(commentText,emailAddress),它会将评论添加到文章中并在不能的情况下抛出异常(由于电子邮件格式无效,文章已关闭,评论未填写或太多等等...)
  • 但现在我不知道保存添加的评论的最佳方法是什么?

我应该像articleRepository.Save(文章)那样做吗?但是,如果只添加评论,为什么要保存文章呢?或者我可以做一些像articleRepository.SaveComment(评论),只会保存评论?或者你会采取什么方法?

谢谢!

2 个答案:

答案 0 :(得分:8)

正如MattDavey指出的那样,在DDD中,您通常会考虑Aggregate生命周期,而不是CRUD持久性问题。 Aggregate的生命中期和结束时由相应的Repository处理。关于你的具体问题:

  

但现在我不知道保存添加的评论的最佳方法是什么?

处理此问题的最佳方法是找到可靠的ORM并实施

articles.MakePersistent(article)

使用此ORM的存储库方法。好的ORM将实现UnitOfWork,包括脏跟踪,延迟加载和其他与持久性相关的问题,而不会限制域对象。 ORM知道如何在保存聚合时避免不需要的SQL INSERT / UPDATE。您的域对象应尽可能持久无知。例如,NHibernate对您的对象施加的唯一约束是它们应该具有私有默认构造函数。除此之外,他们可以是简单的POCO对象,不知道所有持久性问题。要清除,域对象不应该有IsTransientIsDirty标志。如果你发现自己编写使用这些标志的代码,那么你就是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);
                }
            }
        }
    }
}