21

我不太了解 DDD 存储库模式,但 Spring 中的实现让我感到困惑。

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

由于接口扩展了 JpaRepository(或 MongoDBRepository...),如果您从一个 db 更改为另一个,您也必须更改接口。

对我来说,有一个接口可以提供一些抽象,但在这里它不是那么抽象......

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

4

3 回答 3

11

你是对的,从外部的角度来看,接口是对所有实现类都有效的东西的抽象。

这正是这里发生的事情:

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

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

所以对我来说它看起来很正常。

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

于 2011-05-12T08:38:20.993 回答
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,我节省了编写自己的实现类的工作。

于 2011-05-18T19:52:53.697 回答
3

在 Spring Data 的 M2 之前,我们要求用户扩展JpaRepository,原因如下:

  1. 类路径扫描基础架构只选择扩展该接口的接口,因为可能会并行使用 Spring Data JPA 和 Spring Data Mongo,并且它们都指向同一个包,因此不清楚要为哪个存储创建代理。然而,自从 RC1 以来,我们只是将这个负担留给了开发人员,因为我们认为这是一个相当奇特的案例,并且仅使用Repository,CrudRepository或类似的好处超过了您在刚刚描述的极端案例中所付出的努力。您可以使用命名空间中的excludeinclude元素来对此进行更细粒度的控制。
  2. 在 M2 之前,我们通过重新声明 CRUD 方法并用@Transactional. 这个决定反过来是由AnnotationTransactionAttributeSource用于查找事务配置的算法驱动的。因为我们希望通过在具体的存储库接口中重新声明一个 CRUD 方法并应用@Transactional它来为用户提供重新配置事务的可能性。对于 RC1,我们决定实现一个自定义TransactionAttributeSource,以便能够将注释移回存储库 CRUD 实现。

长话短说,这就是它归结为:

从 RC1 开始,不再需要扩展特定于商店的存储库接口,除非您想……</p>

  1. 在更核心的存储库接口中使用List-based 访问findAll(…)而不是-based 访问Iterable(尽管您可以简单地在公共基本接口中重新声明相关方法以返回Lists )
  2. 您想使用 JPA 特定的方法saveAndFlush(…),诸如此类。

一般来说,自 RC1 以来,您在 CRUD 方法的公开方面更加灵活,因为您甚至可以仅扩展Repository标记接口并有选择地添加您想要公开的 CRUD 方法。由于支持实现仍将实现所有方法,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);
}

在该示例中,我们定义MyBaseRepository为仅公开findAll()findOne(…)(将被路由到实现 CRUD 方法的实例中)以及向两个 CRUD 方法添加 finder 方法的具体存储库。

有关该主题的更多详细信息,请参阅参考文档

于 2011-07-06T05:52:21.147 回答