我正在学习领域驱动设计。我目前正在尝试用 C# 编写一个简单的应用程序,使用 DDD 进行设计。该应用程序有一个聚合根 A,它可以包含 0..n 个子实体 B。这可以用以下内容表示:
class A {
public int Id { get; }
public IList<B> { get; }
}
带有存储库:
class ARepository {
public A Get(int id) { ... }
public void SaveOrUpdate(A root) { ... }
public void Delete(A root) { ... }
}
但是,我想在呈现给定 A 实例的 B 子实体时添加分页。我该怎么做呢?我能想到的最好的办法是将 A 和 ARepository 更改为:
class A {
public int Id { get; }
}
class ARepository {
public A Get(int id) { ... }
public void SaveOrUpdate(A root) { ... }
public void Delete(A root) { ... }
public IList<B> GetBForA(A root, int offset, int pageSize, out int numPages) { ... }
}
这当然可行,但我会失去领域模型的简单性和优雅性。
如何使用存储库模式处理子实体分页的最佳实践是什么?我不是在寻找如何使用特定的库等来处理这个问题,而是寻找一种在“模式级别”上处理它的方法。
简短的回答是你不应该这样做。存储库的目的是使域对象的访问变得明确。它们不应用于出于 UI 目的对数据进行分页。这是完全不同的角色,我称之为Finder。为什么?您不想用分页等 UI 概念污染您的域(存储库属于域)。您可以在我的博客此处找到更详细的解释。
如果您使用像 NHibernate 这样的 ORM,您可以通过设置集合属性 (IList) 延迟加载来实现此目的,并在对象本身而不是存储库上急切地获取所需的页面或条件。例如:
var a = ARepository.Get(1);
var secondPageOfBs = a.BList.AsQueryable()
.OrderBy(c => c.Name)
.Skip(PageSize * 2)
.Take(PageSize)
.ToList();
您还可以在存储库中构建这些查询并在域对象中获取结果,例如:
var a = ARepository.GetWithPagedChildren(1, PageSize * 2, PageSize);
您还可以构建更复杂的急切查询,如下所示: http://ayende.com/blog/4367/eagerly-loading-entity-associations-efficiently-with-nhibernate