【问题标题】:Aggregate roots, should they be responsible for deleting child objects?聚合根,他们应该负责删除子对象吗?
【发布时间】:2013-02-22 07:48:50
【问题描述】:

我有一个关于聚合根的问题,他们应该负责删除子对象还是应该由存储库负责?如果我想通过 Id 查询一个文件,我应该在我的存储库中为此创建一个特定的方法吗?

我的聚合根的代码 sn-p:

public class Folder {

   #region Properties

   public Guid Id { get;set; }
   public Name { get;set; }
   public virtual ICollection<File> Files { get;set; }

   #endregion

   #region Methods

   public File AddFile(string type, string title, bool share = false)
   {
     ///
   }

   #endregion
}

文件类:

public class File
{
    #region Properties

    public virtual Folder Folder { get; set; }
    public string Title { get; set; }
    public string Type { get; set; }
    public bool Shared { get; set; }

    #endregion

    #region Constructor

    public File(Folder folder, string type, string title, bool share = false)
    {
        ///
    }

    #endregion
}

谢谢

【问题讨论】:

    标签: domain-driven-design ddd-repositories aggregateroot


    【解决方案1】:

    聚合根负责域不变量(参见http://dddcommunity.org/library/vernon_2011/)。

    所以答案是,聚合根应该是唯一可以访问它聚合的对象的对象。这意味着任何其他对象都不应获得对 File 的引用,并且该 File 不应公开任何更改其自身状态的方法。

    所有改变子对象状态的方法都应该由聚合根本身公开,因为它必须确保聚合不变量。

    关于持久化删除,我通常将域事件建模为 .NET 事件:这些事件在返回实体之前由存储库订阅。因此,在事件处理程序中会发生持久性逻辑(有关详细信息,请参阅http://epic.tesio.it/doc/manual/observable_entities.html

    【讨论】:

    • 你能分享一个在聚合根中使用事件的例子吗?
    • 这里有一个玩具样品:github.com/Shamar/Epic.NET/blob/devel/Challenges/…(但它确实是一个玩具样品)。不幸的是,我无法共享我们域中的代码,因为我不拥有版权。我只能描述它们。例如,AdvisoryContract 公开域事件,例如 RequiringUpdateOfAssetAllocationForInvestmentsInDraft、CustomizedAssetAllocationForInvestmentsInDraft 等,每个事件都在其特定的 EventArgs 中携带有用的信息。事实证明这非常有效。
    • 重申聚合的责任是一个很好的观点,即生成事件。由服务上下文来处理这些事件。
    【解决方案2】:

    这在很大程度上取决于您的上下文。如果文件有自己独立于文件夹的生命周期,那么您可以将文件设为实体/AR。但是,这意味着您需要中断文件夹中的实例聚合关系,以便它仅具有对文件的引用。像这样的:

    public class Folder
    {
        public Guid Id { get;set; }
        public string Name { get;set; }
    
        public List<ContainedFile> Files { get;set; }
    }
    
    
    public class File
    {
        public Guid Id { get;set; }
    
        public string Title { get;set; }
    }
    
    public class ContainedFile // or FolderFIle or whatever makes sense in your domain
    {
        public Guid FileId { get;set; }
    }
    

    尽量将其他 AR 实例的引用排除在 AR 之外。此外,不需要这种双向关系 (File.Folder)。这可能表明您正在使用域模型进行导航:) --- 尽量不要这样做。

    【讨论】:

      【解决方案3】:

      AggregateRoots 应该对其子对象负责。在您的示例中,假设 Folder 公开了 Size 属性,该属性由 Files 大小的总和确定。

      long Size{get{return Files.Sum(f => f.Size);}
      

      因此,当您实际删除文件时,文件夹需要知道它。

      您现在可能没有 Size 属性 - 但遵循 DDD 的部分目的是,当您需要实现它时,它可以简单明了地执行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-07
        • 1970-01-01
        • 2021-10-23
        • 2013-06-20
        相关资源
        最近更新 更多