宣佈適用於 Spring Data 3.0 的 ListCrudRepository 和相關功能

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

Spring Data 的 CrudRepository 擁有多種方法,這些方法返回由 repository 管理的實體例項。它使用 Iterable 而不是 List 來實現,這可能與預期不同。在許多情況下,這並不重要,因為你通常無論如何都需要遍歷結果。但是,你偶爾可能會更喜歡 List。在這種情況下,Iterable 會令人感到不便。

我將更多地闡述最初為何做出這種選擇,以及在你使用 Spring Data 2.x 時如何處理。然而,讓我先公佈好訊息

返回 List 的 Repositories

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);
}

拆分排序 Repositories

常用的 PagingAndSortingRepository 過去繼承自 CrudRepository,但現在不再如此。這允許你將其與 CrudRepositoryListCrudRepository 或你自己建立的基礎介面結合使用。這意味著,即使你已經繼承自 PagingAndSortingRepository,現在也必須顯式地繼承一個 CRUD 片段。

示例 2. 分頁和排序 repository — 2.x 版本

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

示例 3. 分頁和排序 repository — 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 類似,其他排序 repository 介面過去繼承各自的 CRUD 變體,但現在不再如此。

排序片段介面

不再繼承的 CRUD repository

ReactiveSortingRepository

ReactiveCrudRepository

CoroutineSortingRepository

CoroutineCrudRepository

Rx3JavaSortingRepository

Rx3JavaCrudRepository

這意味著,當你使用這些介面中的任何一個作為 Spring Data repositories 的基礎時,現在需要額外繼承相應的 CRUD repository(假設你確實對使用它的 CRUD 功能感興趣)。

2.x 版本怎麼辦?

如果你還沒有準備好嘗試 3.0.0 快照版本,你仍然有所有現有的選項來避免處理返回值為 Iterable 的情況。

  1. 你不需要繼承 CrudRepository。你可以改用 Repository,它沒有任何方法。現在你只需新增你實際想要的方法,並使用你想要的返回型別。如果它們與 CrudRepository 中的方法匹配,但返回 CollectionList 而不是 Iterable,Spring Data 會為你處理轉換。此外,在大多數情況下,你可能在生產環境中並不真正需要 deleteAll,對吧?

  2. 如果你想要 CrudRepository 的所有方法,但希望用其他型別替換 Iterable,你可以透過繼承 CrudRepository 並重寫你想要更改的方法來實現。

  3. 你可以在自己的基礎 repository 介面中實現,而不是在每個宣告的 repository 介面中都這樣做。對於這種方法,使用與上面相同的方法,但用 @NoRepositoryBean 進行註解,這樣 Spring Data 就不會嘗試為其建立實現。你的實際 repository 介面現在可以繼承此介面。流行的 JpaRepository 就是這樣一個介面。

  4. 與上面類似,你可能使用 Streamable 作為返回型別,它是一個 Iterable,但提供了直接轉換為 StreamListSet 的方法。

  5. 如果你不想更改 repositories,可以使用 StreamableIterable 轉換為 StreamListSet 介面。

最初為何選擇 Iterable?

  1. CrudRepository 的方法需要由每個 Spring Data 實現來提供。因此,它不僅是 Spring Data 使用者的 API,也是提供 Spring Data 模組的廠商的 SPI。此外,這樣的模組可能不希望在返回之前填充一個完整的列表,而是快速返回一個 Iterable,同時仍在載入和處理資料。

  2. 如果 CrudRepository 返回 List,你就無法重寫其方法以返回 StreamableSetCollectionIterable

  3. Streamable 本來會是一個很棒的返回型別,因為它兼具靈活性和易用性。不幸的是,它會迫使你在領域模型中使用一個 Spring 介面,許多人認為這是不可接受的,或者至少是一種程式碼異味(code smell)。

此外,一旦 Iterable 已經存在,在不破壞現有程式碼的情況下更改 API 就變得困難甚至不可能。因此,找到一個既提高了易用性,又限制了變更造成的破壞的解決方案花費了一些時間。

我們希望你喜歡這個解決方案,並且我們相信你會將你的想法告訴我們。

獲取 Spring 時事通訊

訂閱 Spring 時事通訊,保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助你加速進步。

瞭解更多

獲取支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案,僅需一個簡單的訂閱。

瞭解更多

近期活動

檢視 Spring 社群的所有近期活動。

檢視全部