In"入门"在Spring Data JPA的例子中,我们创建了一个扩展CrudRepository的接口。但是它只处理一个实体:
import org.springframework.data.repository.CrudRepository;
interface MyEntityRepository extends CrudRepository<MyEntity, Long> {
// methods...
}
在实际应用程序中,有许多实体(表),我们需要为它们执行CRUD操作。使用具有多个(相关或不相关)实体的Spring Data JPA存储库的正确方法是什么?
我是否必须为每个实体创建接口并逐个自动装配(现在这听起来非常疯狂)?
答案 0 :(得分:11)
Spring Data使用域驱动设计中定义的存储库概念。存储库基本上代表聚合根的集合,而聚合根又是您的一些实体,您将访问这些实体并对其他实体施加业务约束。例如。如果您的LineItem
由Order
组成,则LineItem
&#39; d是聚合根,因为它控制Order
等的生命周期。因此,您和& #39; d为LineItem
定义存储库,但不为EntityManager
定义存储库。所以到目前为止,还没有为您创建存储库的所有实体。它在您的域建模中基本上是一个重要的部分,用于决定哪些实体成为聚合根。
另一个方面是存储库通常由持久性机制支持,并且您不希望将业务逻辑直接编码到持久性API,以保持其可测试性,而无需处理持久性API。这意味着,存储库将包含查询方法,这些查询方法基本上表示集合中所有聚合根的子集,并由特定于商店的查询实现支持。这只能通过聚合根方式实现。
第三个也是最后一个方面是,存储库可以帮助您更轻松地限制对持久性操作的访问,因为您可以使用例如包范围强制客户端甚至使用专用服务,并基本上隐藏某个包中某个域对象的所有持久性操作。使用像@Entity
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Forest { ... }
这样的通用持久性API,您无法控制从系统中的任何位置实际读取内容的人,因为它可以在持久性上下文中保留每种类型。
总结一下:存储库代表聚合的集合,并允许访问该集合的专用子集。 Spring Data使这些替代方案尽可能简单,因为替代方案在结构上不太理想(参见上面的推理)或更麻烦(如果必须手动实现)。您创建存储库的实体取决于您对域的建模方式,其中哪些是聚合根。
答案 1 :(得分:2)
你是对的。对于要使用Spring Data的每个实体,您需要创建一个扩展其中一个存储库接口的接口,然后将该接口自动装配到您的类中。您只需要每个实体中的一个您希望执行crud / query操作。如果通过级联关系创建/管理的另一个实体中包含实体,则无需为该实体显式创建存储库。
对于您的观点,必须为每个实体创建一个接口并自动装配它似乎有点冗长,但这就是Spring Data的设计方式,也是它能够为您自动生成数据访问代码的原因。如果你想编写自己的数据层,你显然不必这样做。