考慮以下示例。我有兩個物體:Author和Book. 他們的簽名是:
@Getter
@Setter
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "author")
public class Author implements Serializable {
@Serial
private static final long serialVersionUID = 7626370553439538790L;
@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name", nullable = false)
private String name;
@Default
@OneToMany(fetch = FetchType.LAZY, mappedBy = "author", cascade = CascadeType.ALL)
private Set<Book> books = new HashSet<>();
}
和
@Getter
@Setter
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "book")
public class Book implements Serializable {
@Serial
private static final long serialVersionUID = 4454993533777924839L;
@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name", nullable = false)
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "author_id", nullable = false)
private Author author;
}
我想查詢Author并生成List<AuthorResponse>. 包含與andAuthorResponse相似的屬性,而具有與 相同的屬性。因此,我撰寫了以下代碼:AuthorSet<BookResponse>BookResponseBook
public Uni<List<AuthorResponse>> getAuthors() {
// @formatter:off
return sessionFactory.withSession(
(Session session) -> {
CriteriaBuilder criteriaBuilder = sessionFactory.getCriteriaBuilder();
CriteriaQuery<Author> criteriaQuery = criteriaBuilder.createQuery(Author.class);
Root<Author> authorTable = criteriaQuery.from(Author.class);
criteriaQuery.select(authorTable);
Query<Author> query = session.createQuery(criteriaQuery);
query.setFirstResult(0);
query.setMaxResults(10);
return query.getResultList()
.onItem()
.transform(
(List<Author> authors) -> authors
.stream()
.map(
(Author author) -> AuthorResponse.builder()
.id(author.getId())
.name(author.getName())
.books(
author.getBooks()
.stream()
.map(
(Book book) -> BookResponse.builder()
.id(book.getId())
.name(book.getName())
.build()
)
.collect(Collectors.toSet())
)
.build()
)
.collect(Collectors.toList())
);
}
);
// @formatter:on
}
代碼author.getBooks()清楚地拋出LazyInitializationException,除非我沒有用session.fetch()或明確初始化它Mutiny.fetch()。問題是在上述代碼鏈中呼叫這兩種方法中的任何一種都不合適,因為它回傳 Uni<Set<Book>>,除非我執行以下操作:
Mutiny.fetch(author.getBooks())
.onItem()
.transform(
(Set<Book> books) -> books.stream()
.map(
(Book book) -> BookResponse.builder()
.id(book.getId())
.name(book.getName())
.build()
)
.collect(Collectors.toSet()))
.await()
.indefinitely()
顯然,這是反應性的反模式(如果我的理解是正確的)。
因此,為了減輕上述情況,我使用EntityGraph如下:
EntityGraph<Author> entityGraph = session.createEntityGraph(Author.class);
entityGraph.addAttributeNodes("book");
Query<Author> query = session.createQuery(criteriaQuery);
query.setPlan(entityGraph);
之后,它正在作業。
我想知道EntityGraph在這種情況下使用是否是一個好習慣。或者有沒有更好的方法?
任何建議,將不勝感激。
問候,小吃
uj5u.com熱心網友回復:
我已經在 GitHub 上回答過了,但我想我會在這里重復一遍。
通常,使用 JPQL 查詢中的急切獲取或EntityGraph是更好的方法,因為您將使用單個查詢加載關聯,并且您已經知道您總是想要關聯。
但是您仍然可以Mutiny.fetch在不阻塞的情況下使用。我會將其轉換Uni<List<Author>>為Multi<Author>:
return query.getResultList()
// Convert the Uni<List<Author> into a Multi<Author>
.onItem().transformToMulti( Multi.createFrom()::iterable )
// For each author fetch the books
.onItem().call( author -> Mutiny.fetch( author.getBooks() ) )
// Now everything has been fetched and you can build the response
.map( this::buildAuthorResponse )
// Convert the Multi<AuthorResponse> into Uni<List<AuthorResponse>>
.collect().asList();
...
private void AuthorResponse buildAuthorResponse(Author author) {
return AuthorResponse.builder()
.id(author.getId())
.name(author.getName())
.books(
author.getBooks()
.stream()
.map(
(Book book) -> BookResponse.builder()
.id(book.getId())
.name(book.getName())
.build()
)
.collect(Collectors.toSet())
)
.build();
}
請注意,如果您使用 Quarkus,可能不需要將結果收集到 a 中Uni<List<AuthorResponse>>,您可以只回傳Multi<AuthorReponse>。
無論如何,所有方法都是有效的,您可以選擇更適合您的用例的方法。請記住,為串列中的每個結果獲取關聯每次都會導致新的查詢,通常不建議這樣做(N 1 問題)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/525687.html
標籤:休眠兵变休眠反应
