宣佈 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,但提供了 直接轉換為 StreamListSet 的方法。

  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 社群所有即將舉行的活動。

檢視所有