保存域实体更改

本文关键字:实体 保存 | 更新日期: 2023-09-27 18:09:06

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

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

我应该做一些像articlerrepository . save (article)这样的事情吗?但是,如果只添加了评论,我为什么要保存文章呢?或者我可以像articlerrepository。savecomment (comment)那样,只保存评论?或者你会采取什么方法?

谢谢!

保存域实体更改

正如MattDavey指出的那样,在DDD中,您通常考虑聚合生命周期,而不是CRUD持久性问题。聚合的生命周期中期和末期由相应的存储库处理。关于你的具体问题:

但是现在我不知道保存添加的注释的最好方法是什么?

处理这个问题的最好方法是找到一个可靠的ORM并实现你的
articles.MakePersistent(article)
使用此ORM的

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

在DDD中,您通常会从聚合根向下获取整个组合层次结构,并将其视为单个实体。因此,采用这种心态,"如果只添加了评论,我为什么要保存文章?",似乎文章作为一个整体已经改变,并且文章在数据库中的表示是陈旧的。理想情况下,您可以替换数据库中的整个组合层次结构(使用文档数据库就可以了),但是这可能会导致关系数据库中的性能问题。

在这种情况下,您可能决定让存储库扫描实体的组合,聚合根向下,并智能地决定如何处理每个组件。您可以使用访问者模式遍历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);
                }
            }
        }
    }
}