存储库模式:如何延迟加载? 或者,我应该拆分这个聚合?

我有一个领域模型,有一个编辑器和一个项目的概念。

编辑拥有一些项目,一个项目不仅有一个编辑所有者,而且还有一些编辑成员。 因此,编辑也有一些“join”的项目。

我正在采取DDD方法来build模,并使用Repository模式进行持久化。 但是,我并没有足够好的认识这个模式,以确定我应该怎么做。

我正在假设编辑器和项目可能在相同的聚合,其中根是编辑器。 因此,我可以得到一个编辑,然后列举它的项目,并可以从那里列举项目的成员编辑。

但是,如果我只允许从我的存储库中检索编辑器,那么这是否意味着当我拥有它们的编辑器时,我不得不从存储库中加载所有的项目? 如果我想懒加载成员编辑器,项目需要一个参考资料库以及?

另外,如果我拆分聚合,并有一个编辑器存储库和一个项目存储库,我应该如何处理这两个事务,例如当一个新的项目被添加到编辑器? 例如:

Editor e = new Editor("Editor Name"); editorRepository.Add(e); Project p = e.CreateProject("Project Name"); projectRepository.Add(p); // These two lines editorRepository.Save(e); // should be atomic 

我误解了Repository模式的意图吗?

我误解了Repository模式的意图吗?

我会说“是的”,但是要知道我和每一个和我一起工作的人都有同样的理由要求同一个理由…… “你不是第四维的,Marty。

让我们简化一下,坚持使用构造函数而不是先创build方法:

 Editor e = new Editor("Editor Name"); e = editorRepository.Add(e); Project p = new Project("Project Name", e); p = projectRepository.Add(p); 

在下面,你创build的项目数据库总是将一个有效的所有者( p.EditorId )存储到项目数据中,但是如果你重新填充一个编辑器的项目,它将会在那里。 这就是为什么把所有必需的属性放入构造函数是一个好习惯。 如果你不想传递整个对象,只要e.Id就可以了。

如果我想懒加载成员编辑器,项目需要一个参考资料库以及?

现在,关于如何根据需要重新编辑编辑器的项目,根据您要做什么,您有几个select。 直存储库说,你想要:

 IEnumerable<Project> list = projectRepository.GetAllProjects() .Where(x => x.editorId == e.Id); 

但是把它放在哪里? 不是在项目或编辑器内,你是对的,或者他们将不得不访问存储库,这是不好的。 上面的代码片段是松散耦合的,但是不能自行重用。 您刚刚达到版本库模式的限制。

接下来是适用于您的应用程序的一个适配器层,一个共享源( StaticServiceWrapper )和一些EditorAdapter对象(或Aggregate或任何你会称之为的),或者现在你可以混合扩展方法,可以与任何和所有必要的知识库stream利。 我在生产系统中并没有完全按照这种方式来做,而是向你展示一个简明的例子:

 public static class Aggregators { // one to one, easy public static Editor GetOwner(this Project p) { return StaticServiceWrapper.editorRep.GetEditorById(p.editorId); } // one to many, medium public static IEnumerable<Project> GetProjects(this Editor e) { return StaticServiceWrapper.projectRep.GetAllProjects() .Where(x => x.editorId == e.Id); } // many to many, harder public static IEnumerable<Editor> GetMembers(this Project p) { var list = StaticServiceWrapper.projectMemberMap.GetAllMemberMaps() .Where(x => x.projectId == p.projectId); foreach ( var item in list ) yield return StaticServiceWrapper.editorRep.GetEditorById(item.editorId); } } 

基本上,一旦你的GetAll,GetById,Add,Update,Remove Object Repository完成,你必须离开这些关联,并把对象/图层层次移到有趣的部分,比如Adapters和Caches以及Business Logic( “哦,我的!“ )。

把责任分解成一个EditorOwner和一个EditorMember?

不知道你的领域,我想他们会有不同的责任 – 例如,EditorOwner可能是相当丰富的(也可能是聚合根),但是项目可能只需要知道有限的成员数量,所以EditorMember对象可能很轻。

这些域对象也可能与用户有关,但是这将在另一个上下文中。

这是否有帮助,或只是使其更复杂?

这取决于您的应用程序的需求。 如果为一个给定的编辑器加载所有的项目是一个大问题,那么尝试一个像虚拟代理一样的延迟加载模式。

关于懒惰地加载一个项目的成员编辑,如果你使用虚拟代理,我没有看到一个问题注入与EditorRepository的代理,因为我不认为代理是域的一部分。

如果你分解了Aggregate,你可以把Unit of Work模式作为一个primefaces性的解决scheme。 但是,这个问题并不是DDD所特有的,我相信还有其他的交易行为解决scheme。

在这里你有两种不同的关系,一种是所有权,一种是成员资格。

所有权关系是很简单的(每个项目都有一个所有者)。 会员关系是多对多的(项目编辑多,编辑多的项目)。

您可以在Project类上提供Owner属性,并在ProjectRepository上提供一个方法来获取由特定编辑器拥有的所有项目。

对于许多关系,请在Project类中提供Members属性,并在ProjectRepository上提供一个方法来获取包含指定Editor的所有项目作为成员。

编辑器和项目似乎也是实体,我可能会拆分集合,但也许这些条款在您的上下文中具有特定含义,使其成为聚合的子实体。