簡體   English   中英

OneToMany 需要采集數據時的惰性初始化

[英]OneToMany lazy initialization when needing collection data

如果我有關系OneToMany並想訪問延遲加載的集合,有什么解決方法? 目前我得到LazyInitializationException有這個:

Club實體:

@Entity
public class Club {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    @OneToMany(mappedBy = "club", cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
    @JsonBackReference
    private List<Player> players;

Player實體:

有兩種方法是不是一個好主意,一種是在沒有玩家的情況下獲取數據,另一種是也獲取玩家的數據?

    @Override
    List<Club> findAll();

    @Query("Select clubs from Club clubs left join fetch clubs.players")
    List<Club> getAllClubsWithPlayers();

我在想的是,這是一個壞主意,因為如果我遇到這樣一種情況,例如我有 4 個延遲加載的屬性,並且我一次需要其中的 3 個,我將不得不進行查詢像: getAllClubsWithPlayersAndSponsorsAndCoaches ,所以我必須有很多這樣的查詢組合。 我不想使用EAGER ,所以如果我有時需要訪問Clubplayers ,這是否是一種常見的方法,那么您能告訴我這是不是一種常見的方法嗎?這可以通過拋出LazyInitializationExceptionfindAll()方法來撤消?

不要誤解我的意思——我知道LazyInitializationException是從哪里來的,但我只是不知道如果我在獲取clubs時有時需要他們,訪問players的最佳方式是什么。 我的做法是否正確?

有3個選擇:

  1. 訪問@Transactional方法中的所有惰性字段。 你不顯示你的代碼,但通常有一個 Service Facade 層負責@Transactional 它調用存儲庫。
  2. 編寫一個查詢來獲取所有需要的數據。 然后,您必須專門創建一個方法來獲取該邏輯所需的所有惰性字段。
  3. 使用 OpenSessionInViewFilter 或 OpenSessionInViewInterceptor 以便在執行甚至到達 Controller 之前啟動 Session/EntityManager。然后 Session 將在請求處理結束時由同一高層關閉。

除了 Stanislav 所寫的內容之外,我還想詳細說明他的第二點,因為我認為這通常是最好的方法 - 這只是因為它可以節省對數據庫的不必要調用,從而提高性能。

除了在您的存儲庫中為每個用例編寫單獨的 JPQL 查詢之外,您還可以執行以下操作之一:

  1. 使您的存儲庫擴展JpaSpecificationExecutor並以編程方式描述需要獲取的內容,如本答案中所述

  2. 使用使用注釋描述或以編程方式描述的實體圖,並使用EntityManager獲取您的實體,如本教程中所述

要有選擇地加載您想要的內容,您可以使用 EntityGraph。

在您的實體中聲明@NamedEntityGraph

@Entity
@NamedEntityGraph(name = "Club.players",
    attributeNodes = @NamedAttributeNode("players")
)
public class Club {

然后你應該用這個圖的名字來注釋你的findAll()方法

@EntityGraph(value = "Club.players")
List<Club> findAll();

但是,這會覆蓋您的基本findAll()方法。 為避免這種情況(同時具有兩種實現方式),您可以采用以下方式:

https://mvnrepository.com/artifact/com.cosium.spring.data/spring-data-jpa-entity-graph/<version>添加依賴

然后將您的存儲庫替換為

@Repository
public interface ClubRepository extends JpaSpecificationExecutor<Club>, JpaRepository<Club, Long>, EntityGraphJpaSpecificationExecutor<Club> {

}

然后您將擁有基本方法findAll()並且還可以從您的服務中調用

List<Club> clubs = clubRepository.findAll(specification, new NamedEntityGraph(EntityGraphType.FETCH, "Club.players"))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM