宣布 Spring Data 3.0 的 ListCrudRepository 及其相关功能

工程 | Jens Schauder | 2022年2月22日 | ...

Spring Data 的 CrudRepository 具有多种返回存储库管理的实体多个实例的方法。它通过使用 Iterable 而不是像预期的那样使用 List 来实现。在许多情况下,这无关紧要,因为您通常无论如何都希望迭代结果。但是,您有时可能更喜欢 List。在这些情况下,Iterable 令人烦恼。

我将详细介绍为什么最初做出这样的选择以及如何在 Spring Data 2.x 上处理它。但是,让我先说一下好消息

返回列表的存储库

Spring Data 3.0.0 现在在最新的快照版本中提供了一个 ListCrudRepository,它在 CrudRepository 返回 Iterable 的地方返回 List

示例 1. CrudRepository 与 ListCrudRepository

@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {

	<S extends T> S save(S entity);

	<S extends T> Iterable<S> saveAll(Iterable<S> entities);

	Optional<T> findById(ID id);

	boolean existsById(ID id);

	Iterable<T> findAll();

	Iterable<T> findAllById(Iterable<ID> ids);

	long count();

	void deleteById(ID id);

	void delete(T entity);

	void deleteAllById(Iterable<? extends ID> ids);

	void deleteAll(Iterable<? extends T> entities);

	void deleteAll();
}

@NoRepositoryBean
public interface ListCrudRepository<T, ID> extends CrudRepository<T, ID> {

	<S extends T> List<S> saveAll(Iterable<S> entities);

	List<T> findAll();

	List<T> findAllById(Iterable<ID> ids);
}

拆分排序存储库

流行的 PagingAndSortingRepository 过去扩展自 CrudRepository,但现在不再扩展了。这使您可以将其与 CrudRepositoryListCrudRepository 或您自己创建的基本接口结合使用。这意味着您现在必须显式地扩展自 CRUD 片段,即使您已经扩展自 PagingAndSortingRepository

示例 2. 分页和排序存储库 - 版本 2.x

public interface PersonRepository<Person, Long> extends PagingAndSortingRepository<Person, Long> {}

示例 3. 分页和排序存储库 - 版本 3.x

public interface PersonRepository<Person, Long> extends PagingAndSortingRepository<Person, Long>, ListCrudRepository<Person, Long> {}

还有一些其他返回 Iterable<T> 的接口,现在也获得了返回 List<T> 的配套接口。

返回 Iterable 的片段接口

返回 List 的新片段接口

QuerydslPredicateExecutor

ListQuerydslPredicateExecutor

QueryByExampleExecutor

ListQueryByExampleExecutor

此外,类似于 PagingAndSortingRepository,其他排序存储库接口过去扩展自它们各自的 CRUD 变体,但现在不再这样做。

排序片段接口

它不再扩展的 CRUD 存储库

ReactiveSortingRepository

ReactiveCrudRepository

CoroutineSortingRepository

CoroutineCrudRepository

Rx3JavaSortingRepository

Rx3JavaCrudRepository

这意味着,当您使用这些接口中的任何一个作为 Spring Data 存储库的基础时,您现在需要额外扩展相应的 CRUD 存储库(假设您实际上有兴趣使用它的 CRUD 功能)。

2.x 怎么办?

如果您还没有准备好切换到 3.0.0 快照版本,您仍然可以使用所有 现有选项 来避免处理 Iterable 作为返回值。

  1. 您无需扩展 CrudRepository。您可以改为使用 Repository,它没有任何方法。现在,您可以仅添加实际需要的方法以及所需的返回类型。如果它们与 CrudRepository 中的方法匹配,但返回 CollectionList 而不是 Iterable,Spring Data 会为您处理转换。此外,在大多数情况下,您可能真的不需要在生产环境中使用 deleteAll,对吧?

  2. 如果您想要 CrudRepository 的所有方法,但希望将 Iterable 替换为其他内容,您可以通过扩展 CrudRepository 并覆盖要更改的方法来实现。

  3. 无需在声明的每个存储库接口中执行此操作,您可以创建自己的基本存储库接口。对于这种方法,请使用与上述相同的方法,但使用 @NoRepositoryBean 注释它,以便 Spring Data 不尝试为此创建实现。您实际的存储库接口现在可以扩展自此接口。流行的 JpaRepository 就是这样的一个接口。

  4. 与上述相同的方式,您可以使用 Streamable 作为返回类型,它是一个 Iterable,但提供了 直接转换为 Stream 的方法ListSet

  5. 如果您不想触碰存储库,您可以使用 StreamableIterable 转换为 StreamListSet 的接口

为什么一开始使用 Iterable?

  1. CrudRepository 的方法需要由每个 Spring Data 实现来实现。因此,它不仅是 Spring Data 用户的 API,也是为提供 Spring Data 模块的人员提供的 SPI。此外,此类模块可能不希望在返回之前填充完整列表,而是希望快速返回 Iterable,同时仍然加载和处理数据。

  2. 如果 CrudRepository 返回 List,则您无法覆盖其方法以返回 StreamableSetCollectionIterable

  3. Streamable 本可以成为一个很好的返回类型,因为它结合了灵活性和可用性。不幸的是,它会将 Spring 接口强制到您的领域模型中,许多人认为这是不可取的,或者至少是一种代码异味。

此外,一旦 Iterable 发布,更改 API 就会变得困难甚至不可能,因为这会导致现有代码中断。因此,找到一种在限制更改导致的破坏的同时提高可用性的解决方案需要一些时间。

我们希望您喜欢这个解决方案,并且相信您会告诉我们您的想法。

获取 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,以加速您的进步。

了解更多

获取支持

Tanzu Spring 在一个简单的订阅中提供对 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部