使用JPA实体作为域实体的洋葱架构

时间:2020-04-13 17:54:52

标签: spring jpa orm onion-architecture

我一直在努力选择将JPA实体作为单独的类,而不是在单个有界上下文中与域实体一起使用。我面临以下选择

对带有域存储库的聚合根/Aggregates..etc使用单独的域类来包装Spring JPA存储库,并使用转换器映射JPA实体<>仅包含必需数据的域实体

  • 除非在映射器/转换器中在域存储库中处理此延迟,否则将放弃惰性加载,但这太过分了。

  • 保存对象时,可能会有相关的聚合根(一对多关系),后来以复杂的逻辑进行处理,我不得不极端地关心Domain实体的状态,以将其传递给域存储库,或者用所有相关数据填充它,或者简单地将其映射(在转换器中的另一种方法),而没有关系数据(级联不适用于JPA持久化)

  • 即使在非常简单的用例中,也有很多重复的代码可以避免这种情况

或者使用JPA实体作为我的域实体,到目前为止,有很多类似的示例/观点

https://github.com/citerus/dddsample-core/tree/Spring_Annotations_Autowire

http://www.javamagazine.mozaicreader.com/MayJune2018/Twitter#&pageSet=50&page=0

Should JPA entities and DDD entities be the same classes?

DDD, domain entities/VO and JPA

How to implement DDD using Spring Crud/Jpa Repository

另一方面,有这样的观点

Is it a good practice to use JPA entities as domain models?

从长远来看,我的问题来自经验

  • 什么会花费更多的精力和时间?
  • 两种方法都可以接受吗?
  • 两者的优缺点是什么?

1 个答案:

答案 0 :(得分:1)

什么会花费更多的精力和时间?

去耦几乎总是如此。这是个权衡!

两种方法都可以接受吗?

是的。我看到两种方法都有很多矛盾的意见,但实际上,它们只是意见而已。两者都适用且成本高。

两者的优缺点是什么?

将JPA实体用作域实体实际上确实在1上减少了时间成本。 2-还可以让您将延迟加载与关系一起使用,从而避免了应用程序服务中的更多代码,如果您不是按照id来引用其他聚合,那么这也是基于意见的,但实际上会浪费JPA。

这种方法的缺点是我认为它是单元测试。单元测试不应依赖于启动容器,数据库等。应该纯粹测试业务逻辑。但是,使用这样的框架并不是不可能的。例如,请参见此答案

JPA Entity must be unit tested and how?

将JPA用作具有包装器存储库的基础结构中的独立实体,将使单元测试更容易模拟数据并轻松地测试纯域(业务规则)。与以前的优点相反,它将花费您大量的映射工作和时间,太多的重复代码用于映射,包装存储库等。照顾域实体的状态令人头疼(这应该是专家),因为将null映射到JPA实体会影响到映射到持久性源的关系,并且您应该全面照顾 >表示域实体的状态。

也不会轻易使用ORM的自动延迟加载。要么

1-您在聚合根目录中引用了其他聚合作为成员(违反了聚合ID引用规则),并在映射器中进行处理

2-您可以从存储库中获得仅需要聚合根的所需数据,而其他聚合ID作为参考成员。这是通过存储库实现中定义良好的查询完成的,因此,这是很多编写和自定义查询的过程。避免使用默认实例,该默认实例会返回完整的JPA实体,并具有与延迟加载相关的参考。