C# 保存域实体更改

C# 保存域实体更改,c#,domain-driven-design,repository,entity,cqrs,C#,Domain Driven Design,Repository,Entity,Cqrs,这里有一个真正的例子可以引出我的问题:我有一个AddCommentToArticleCommand,它有一个ArticleId、注释文本和电子邮件地址。此命令: 使用文章存储库获取文章(即域实体) 如果文章存在,它会调用article.AddComment(commentText,emailAddress),这会将评论添加到文章中,如果无法添加,则会引发异常(由于电子邮件格式无效、文章已关闭、评论未填写或太长等原因) 但现在我不知道保存添加的评论的最佳方法是什么 我应该像articleRep

这里有一个真正的例子可以引出我的问题:我有一个AddCommentToArticleCommand,它有一个ArticleId、注释文本和电子邮件地址。此命令:

  • 使用文章存储库获取文章(即域实体)
  • 如果文章存在,它会调用article.AddComment(commentText,emailAddress),这会将评论添加到文章中,如果无法添加,则会引发异常(由于电子邮件格式无效、文章已关闭、评论未填写或太长等原因)
  • 但现在我不知道保存添加的评论的最佳方法是什么
我应该像articleRepository.Save(文章)这样做吗?但是,如果只添加了一条评论,我为什么要保存这篇文章呢?或者我可以做一些像articleRepository.SaveComment(comment)这样的操作,只保存注释吗?或者你会采取什么方法


谢谢

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

在这种情况下,您可能会决定让存储库扫描实体的组成,向下聚合根,并智能地决定如何处理每个组件。您可以使用访问者模式对注释对象进行迭代,并根据它们是否是暂时的/脏的,决定执行插入或更新,或者干脆不处理它们

我希望我已经足够清楚了,我不太擅长解释概念性的东西:)

编辑:代码示例:

// 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);
                }
            }
        }
    }
}
正如所指出的,在DDD中,您通常考虑生命周期,而不是CRUD持久性问题。骨料的寿命中期和末期由相应的处理程序处理。关于你的具体问题:

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

处理这个问题的最好方法是找到一个可靠的ORM并实现

articles.MakePersistent(article)

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

谢谢!所以我猜这意味着如果属性发生变化,实体应该更新这些IsTransient和IsDirty属性;存储库负责在保存实体后重置它们?是的,请查看System.ComponentModel.IChangeTracking界面。IsTransient/IsPersistant有时可以分别通过缺少/存在主键值来推断。在我的实体中,我也经常实现ISupportInitialize,当实体初始化时,更改属性不会使实体变脏(或引发属性更改事件等)。这也很方便:)但是如果有钥匙,我不需要IsTransient,我想-我可以检查id,如果是0,这意味着IsTransient是真的。。。所以IChangeTracking看起来已经足够好了……好吧,我只是给每个实体添加了一个EntityState,可以是新的、修改的、删除的、未修改的。基于此,articlerepository做出了决定……你的评论帮助了我,因为我意识到我在做已经存在的事情。所以我改变了方法:我首先使用实体框架和代码;实行单位工作制。现在EF上下文为我保留了更改。谢谢你的反馈@Dmitry+1这是一个非常有效的观点。在我的特殊情况下,我无法对正在使用的ORM的功能做出任何假设(它甚至可能不是ORM),因此在域中实现诸如更改跟踪之类的事情对我来说是有意义的。如果您与ORM实现有足够的联系,可以可靠地利用它的功能,那么这样做当然很有意义:)实际上,我的域不依赖于ORM或其他任何东西。它是洋葱建筑的中心。围绕它构建的工作单元依赖于ORM,并使用其上下文进行更改跟踪。但是域只有域逻辑…@Dmitry我下面的回答(这显然违反了持续无知的原则)与DDD相矛盾吗?以我的场景为例,正如我所提到的,我不能对数据访问层的功能做出任何假设。。在DDD中,将变更跟踪等功能提升到域模型中有意义吗?或者在域模型和DAL之间应该有另一层来处理类似的事情(延迟加载、工作单元等)`@Lud很抱歉劫持了你的问题,但我真的很想知道我的答案哪里错了:)我想是的,因为更改跟踪是一个持久性问题,不应该在你的域上“流血”。它应该由ORM实现,无论您是在使用现有的ORM还是试图构建自己的ORM。如果没有ORM,构建将对象持久化到关系数据库中的域层是非常困难的。您的对象将变得越来越具有持久性意识,并失去对域的关注。然而,在大多数“自主开发”的ORM项目上也会发生同样的事情。将更改跟踪放在域中是非常困难的