4

我正在尝试不费吹灰之力地实现完全有效的持久性无知。不过我有很多问题:

最简单的选择

这真的很简单——可以像在 SOA 中那样使用 Spring Data 注释对实体进行注释(但让它们真正执行逻辑)?除了必须在实体中使用持久性注释之外还有什么后果,这并不真正遵循 PI 原则?我的意思是 Spring Data 真的是这样 - 它提供了很好的存储库,可以完成 DDD 中的存储库应该做的事情。问题在于实体本身......

更难的选择

为了使实体不知道它所操作的数据来自何处,很自然地通过构造函数将该数据作为接口注入。另一个优点是我们总是可以执行延迟加载——例如,我们在 Neo4j 图形数据库中默认拥有。缺点是聚合(由实体组成)将完全了解所有数据,即使它们不使用它们 - 由于数据完全暴露,可能会导致调试困难(DAO 将像聚合一样是分层的)。这也将迫使我们为存储库使用一些适配器,因为它们不再存储真实的实体......而且任何翻译都很丑陋......另一件事是我们无法在没有这样的 DAO 的情况下实例化实体 - 尽管可能存在-域中的内存实现......再次,更多层。

最难的选择

实体可以包裹在一个决定数据应该来自哪里的延迟加载器上。它可以是内存中的,也可以是数据库中的,它可以处理任何需要事务的操作等等。虽然是复杂的层,但在某种程度上可能是通用的......?在这里阅读

你知道其他解决方案吗?或者,也许我在提到的那些中遗漏了一些东西。请分享你的想法!

4

4 回答 4

14

作为正确域建模的副作用,我(几乎)免费实现了持久性无知。

尤其是:

  • 如果您正确定义每个上下文的边界,您将获得不需要延迟加载的小实体(这实际上成为 DDD 项目中的反模式/代码气味)
  • 如果您不能简单地在存储库中使用 SQL,请将一组 DTO 映射到您的数据库模式,并将它们用于工厂以初始化实体类。

在 DDD 项目中,持久性无知与领域模型本身相关,与存储库、工厂和其他应用程序代码无关。实际上,您将来不太可能更改 ORM 和/或数据库。

对域模型的持久性无知背后唯一(但非常强大)的理性是关注点分离:在域模型中,您应该表达业务不变量!持久性是一个基础设施问题!

例如,如果没有持久性无知(以及延迟加载),域模型应该处理来自数据库的可能异常,它的复杂性会增加,并且业务规则会隐藏在技术细节下。

于 2013-08-21T08:08:47.047 回答
7

就我个人而言,当尝试使用与 ORM 相同的实体时,我发现几乎不可能实现干净的域模型。

我的解决方案是按照我认为合适的方式对我的域实体进行建模,并确保任何 ORM 实体都不会泄漏到存储库之外。这意味着我的存储库接受并返回域实体。

这意味着您将失去“大部分 ORM 优点”并最终“使用您的 ORM 进行简单的 CRUD 操作”。

这两种权衡对我来说都很好,我宁愿有一个我可以使用的干净的域模型,而不是一个被我的数据库或 ORM 中的人工制品污染的域模型。它还将我“与我的 ORM 搏斗”所花费的时间减少到零。

作为旁注,我发现文档数据库更适合 DDD。

于 2013-08-21T09:34:08.223 回答
1

除非我撞到石墙,否则我会采用最简单的选择。当你采用 pi 原理时,也存在这样的陷阱

有时一些妥协是可以接受的。

public class Order {
    private String status;//my orm does not support enum

    public Status status() {
        return Status.of(this.status);
    }

    public is(Status status) {
        return status() == status;//use status() instead of getStatus() in domain model
    }
}
于 2013-08-21T07:45:32.697 回答
1

一旦您将在域模型中提供持久性映射:

  • 您的代码取决于框架。如果你决定改变这个框架,你想改变持久层和模型层的源代码——更多的工作、更多的改变、更多的代码合并等等。
  • 您的域模型 jar 文件取决于 spring/nhibernate jar 等。
  • 您的类变得越来越大,业务代码和持久性相关代码如何增长

我不得不承认我不理解更难和最难的选择。

我们为域实体使用了分离的接口和实现。使用 Hibernate 和存储库提供分离的映射文件。

实体是使用工厂(或以后的存储库)创建的,标识符是在持久层中生成的,实体在持久化之前不需要它。

延迟加载由List一次的特殊实现提供:

  1. 实体的映射包含它
  2. 从持久层获取实体/聚合

唯一的问题与事务有关,因为当您在事务范围之外使用延迟加载的集合时,它会失败。

于 2013-08-21T07:30:46.033 回答