对Spring-Data DDD存储库模式感到困惑

时间:2011-05-12 08:17:08

标签: spring domain-driven-design nosql repository-pattern spring-data

我对DDD存储库模式了解不多,但Spring中的实现让我很困惑。

public interface PersonRepository extends JpaRepository<Person, Long> { … }

当接口扩展JpaRepository(或MongoDBRepository ...)时,如果从一个db更改为另一个db,则还必须更改接口。

对我来说,一个接口可以提供一些抽象,但这里并没有那么抽象......

你知道为什么Spring-Data会这样吗?

3 个答案:

答案 0 :(得分:11)

你是对的,从外部的角度来看,接口是关于所有实现类的工作的抽象。

这就是这里发生的事情:

  • JpaRepository是所有JPA存储库的通用视图(适用于所有不同的实体),而MongoDBRepository对于所有MongoDB实体都是相同的。
  • 但JpaRepository和MongoDBRepository没有任何共同之处,除了常见的超级接口中定义的东西:

    • org.springframework.data.repository.PagingAndSortingRepository
    • org.springframework.data.repository.Repository

所以对我而言看起来很正常。

如果您使用实现存储库的类,那么如果您希望能够从JPA实现切换到基于文档的实现,请使用PagingAndSortingRepository或Repository(抱歉,但我无法想象这样的用例 - 无论如何)。当然,您的Repository实现应该实现正确的接口(JpaRepository,MongoDBRepository),具体取决于它是什么。

答案 1 :(得分:7)

此博客文章http://blog.springsource.com/2011/02/10/getting-started-with-spring-data-jpa/中已明确说明了这背后的原因。

  

定义此接口有两个目的:首先,通过扩展JpaRepository,我们在我们的类型中获得了一堆通用的CRUD方法,允许保存帐户,删除它们等等。其次,这将允许Spring Data JPA存储库基础结构扫描此接口的类路径,并为其创建一个Spring bean。

如果你不信任来源如此接近来源(双关语),那么阅读这篇文章也是一个好主意http://www.brucephillips.name/blog/index.cfm/2011/3/25/Using-Spring-Data-JPA-To-Reduced-Data-Access-Coding

  

我不需要编码的是PersonRepository接口的实现。 Spring将创建此接口的实现,并使PersonRepository bean可以自动连接到我的Service类中。 PersonRepository bean将具有所有标准CRUD方法(将是事务性的)并返回Person对象或Person对象的集合。因此,通过使用Spring Data JPA,我已经保存了自己编写的实现类。

答案 2 :(得分:3)

在Spring数据的M2之前,由于以下原因,我们要求用户扩展JpaRepository

  1. 类路径扫描基础结构只选择扩展该接口的接口,因为可以并行使用Spring Data JPA和Spring Data Mongo,并且它们都指向同一个包,不清楚为哪个存储创建代理服务器。然而,自RC1以来,我们只是将这种负担留给了开发人员,因为我们认为这是一个相当奇特的案例,只需使用RepositoryCrudRepository或类似的权益,就可以超越您刚才所描述的努力。角落案件。您可以使用命名空间中的excludeinclude元素来对此进行更精细的控制。
  2. 在M2之前,我们通过重新声明CRUD方法并使用@Transactional注释它们来将事务性应用于CRUD方法。反过来,这个决定是由AnnotationTransactionAttributeSource用于查找事务配置的算法驱动的。我们希望通过在具体的存储库界面中重新声明CRUD方法并在其上应用@Transactional来为用户提供重新配置事务的可能性。对于RC1,我们决定实现自定义TransactionAttributeSource,以便能够将注释移回存储库CRUD实现。
  3. 长话短说,这就是它归结为:

    从RC1开始,不再需要扩展商店特定的存储库界面,除了你想...

    1. 在更多核心存储库接口中使用基于List的{​​{1}}而不是findAll(…)的访问权限(尽管您可以简单地在公共基础接口中重新声明相关方法也可以返回Iterable
    2. 您希望使用特定于JPA的方法,例如List等。
    3. 一般来说,自RC1以来你对CRUD方法的曝光要灵活得多,因为你甚至可以只扩展saveAndFlush(…)标记界面并有选择地添加你想要公开的CRUD方法。由于支持实现仍将实现Repository的所有方法,我们仍然可以将调用路由到实例:

      PagingAndSortingRepository

      在该示例中,我们将public interface MyBaseRepository<T, ID extends Serializable> extends Repository<T, ID> { List<T> findAll(); T findOne(ID id); } public interface UserRepository extends MyBaseRepository<User, Long> { List<T> findByUsername(String username); } 定义为仅公开MyBaseRepositoryfindAll()(将被路由到实现CRUD方法的实例中)和具体的存储库,将finder方法添加到两个CRUD。

      有关该主题的更多详细信息,请参阅reference documentation