关于聚合根,我有一个问题,他们是否应该负责删除子对象,还是应该归到存储库?如果我想通过其Id查询一个文件,我应该在我的存储库中为此创建一个特定的方法吗?
我的聚合根的代码段:
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
}
由于
答案 0 :(得分:6)
聚合根负责域不变量(请参阅http://dddcommunity.org/library/vernon_2011/)。
所以答案是是,聚合根应该是唯一可以访问它聚合的对象的对象。这意味着没有其他对象应该获取对File的引用,并且该File不应该公开任何改变其自身状态的方法。
所有更改子对象状态的方法都应该由聚合根本身公开,因为它必须确保聚合的不变量。
至于持久删除,我通常将域事件建模为.NET事件:然后在返回实体之前由存储库订阅此类事件。因此,在事件处理程序中会出现持久性逻辑(有关详细信息,请参阅http://epic.tesio.it/doc/manual/observable_entities.html)
答案 1 :(得分:3)
这在很大程度上取决于您的背景。如果文件具有独立于文件夹的生命周期,则可以将文件设置为实体/ 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
)不是必需的。这可能表明您正在使用您的域模型进行导航:) ---尽量不这样做。
答案 2 :(得分:3)
AggregateRoots应该负责他们的子对象。对于您的示例,假设文件夹公开了一个Size属性,该属性是根据文件大小的总和确定的。
long Size{get{return Files.Sum(f => f.Size);}
因此,当您实际删除文件时,该文件夹需要了解它。
你现在可能没有Size属性 - 但是跟随DDD的部分目的是当你需要实现它时,它很容易和干净。