我已經通過 JPA 映射了以下物體:
@Entity(name = "Parent")
@Table(name = "parent")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "type")
public abstract class Parent {
@Id
@GenericGenerator(name = "CustomUUIDGenerator", strategy = "package.CustomUUIDGenerator")
@GeneratedValue(generator = "CustomUUIDGenerator", strategy = GenerationType.AUTO)
private UUID id;
@ManyToMany
@Fetch(FetchMode.JOIN)
@JoinTable(name = "parent_country", joinColumns = @JoinColumn(name = "parent_id"),
inverseJoinColumns = @JoinColumn(name = "country_id"))
private Set<Country> countries;
}
@Entity(name = "ChildA")
@Table(name = "child_a")
@DiscriminatorValue(value = "CHILD_A")
public class ChildA extends Parent {
private String description;
}
這反映到以下 Postgres 的表模式:
表 PARENT 列:ID、TYPE
表 COUNTRY 列:ID、CODE、LANGUAGE
表 PARENT_COUNTRY 列:PARENT_ID、COUNTRY_ID
表 CHILD_A 列:ID、DESCRIPTION
基于此,我正在嘗試創建一個CriteriaQuery用于EntityGraph控制動態關聯物體加載的方法。以下代碼顯示了給定查詢的方式:
EntityGraph<ChildA> entityGraph = entityManager.createEntityGraph(ChildA.class);
entityGraph.addAttributeNodes(Parent_.COUNTRIES);
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<ChildA> criteriaQuery = criteriaBuilder.createQuery(ChildA.class);
Root<ChildA> root = criteriaQuery.from(ChildA.class);
List<Predicate> predicates = new ArrayList<>();
final Join<ChildA, Country> join = root.join(ChildA_.COUNTRIES, JoinType.LEFT);
predicates.add(criteriaBuilder.equal(join.get(Country_.CODE), "USA"));
criteriaQuery.where(predicates.toArray(Predicate[]::new));
TypedQuery<ChildA> finalQuery = entityManager
.createQuery(criteriaQuery)
.setHint(EntityGraphPersistence.LOAD_GRAPH, entityGraph);
List result = finalQuery.getResultList();
問題是,當我運行上面的查詢時,我會在控制臺上列印以下 SQL:
select
* -- All hibernate fields from all entities
from
child_a ca
inner join
parent pa
on ca.id=pa.id
left outer join
parent_country pc
on pc.parent_id = ca.id
left outer join
country co
on pc.country_id = co.id
left outer join
parent_country pc_2
on pc2.parent_id = ca.id
left outer join
country co2
on pc2.country_id = co2.id
where
(
co.code=?
)
上述查詢的問題是 PARENT_COUNTRY 和 COUNTRY 的雙重聯接。在這個查詢中,我根據國家代碼(等于美國)過濾結果,所以我不想從其他國家(不同于美國)的資料庫中回傳。但是,由于第二個左連接到國家,父級再次與國家相關,并且對第一個關系所做的過濾器co.code=?被忽略。
有誰知道如何防止這個用例中的雙重加入?
uj5u.com熱心網友回復:
最后,在為這個問題苦苦掙扎了一整天后,我找到了解決方案。事實證明,解決方案是使用fetch-join從 JPA 呼叫的功能,它允許您加入關系并使用它來獲取將用于填充物體的資料。
然而,必須進行一些語法調整才能使其正常作業。此外,當我使用標準構建器獲取-加入關系時,我也應該從 EntityGraph 中忽略它們,這樣我就不會兩次加入同一個物體。下面的代碼片段顯示了它是如何作業的:
EntityGraph<ChildA> entityGraph = entityManager.createEntityGraph(ChildA.class);
//entityGraph.addAttributeNodes(Parent_.COUNTRIES);
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<ChildA> criteriaQuery = criteriaBuilder.createQuery(ChildA.class);
Root<ChildA> root = criteriaQuery.from(ChildA.class);
List<Predicate> predicates = new ArrayList<>();
//final Join<ChildA, Country> join = root.join(ChildA_.COUNTRIES, JoinType.LEFT);
Fetch<ChildA, Countries> fetch = root.fetch(ChildA_.COUNTRIES, JoinType.LEFT); // new line
Join<ChildA, Countries> join = (Join<ChildA, Countries>) fetch; // new line
predicates.add(criteriaBuilder.equal(join.get(Country_.CODE), "USA"));
criteriaQuery.where(predicates.toArray(Predicate[]::new));
TypedQuery<ChildA> finalQuery = entityManager
.createQuery(criteriaQuery)
.setHint(EntityGraphPersistence.LOAD_GRAPH, entityGraph);
List result = finalQuery.getResultList();
您可以在此鏈接中找到有關此主題的更多詳細資訊:https ://discourse.hibernate.org/t/how-can-i-do-a-join-fetch-in-criteria-api/846/4
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/524361.html
