JPA继承@EntityGraph包括子类的可选关联 [英] JPA inheritance @EntityGraph include optional associations of subclasses
问题描述
鉴于以下域模型,我想加载所有Answer
包括其Value
及其各自的子子级,并将其放入AnswerDTO
中,然后转换为JSON.我有一个可行的解决方案,但是它遇到了N + 1问题,我想通过使用临时@EntityGraph
摆脱它.所有关联都配置为LAZY
.
Given the following domain model, I want to load all Answer
s including their Value
s and their respective sub-children and put it in an AnswerDTO
to then convert to JSON. I have a working solution but it suffers from the N+1 problem that I want to get rid of by using an ad-hoc @EntityGraph
. All associations are configured LAZY
.
@Query("SELECT a FROM Answer a")
@EntityGraph(attributePaths = {"value"})
public List<Answer> findAll();
在Repository
方法上使用临时的@EntityGraph
,我可以确保预先提取值以防止Answer->Value
关联上的N + 1.虽然我的结果还不错,但是还有另一个N + 1问题,因为延迟加载了MCValue
的selected
关联.
Using an ad-hoc @EntityGraph
on the Repository
method I can ensure that the values are pre-fetched to prevent N+1 on the Answer->Value
association. While my result is fine there is another N+1 problem, because of lazy loading the selected
association of the MCValue
s.
使用此
@EntityGraph(attributePaths = {"value.selected"})
失败,因为selected
字段当然只是某些Value
实体的一部分:
fails, because the selected
field is of course only part of some of the Value
entities:
Unable to locate Attribute with the the given name [selected] on this ManagedType [x.model.Value];
如果值是MCValue
,如何告诉JPA仅尝试获取selected
关联?我需要类似optionalAttributePaths
的东西.
How can I tell JPA only try fetching the selected
association in case the value is a MCValue
? I need something like optionalAttributePaths
.
推荐答案
You can only use an EntityGraph
if the association attribute is part of the superclass and by that also part of all subclasses. Otherwise, the EntityGraph
will always fail with the Exception
that you currently get.
避免N + 1选择问题的最佳方法是将查询分为2个查询:
The best way to avoid your N+1 select issue is to split your query into 2 queries:
第一个查询使用MCValue
实体,以获取由selected
属性映射的关联.在查询之后,这些实体随后存储在Hibernate的1级缓存/持久性上下文中. Hibernate在处理第二个查询的结果时将使用它们.
The 1st query fetches the MCValue
entities using an EntityGraph
to fetch the association mapped by the selected
attribute. After that query, these entities are then stored in Hibernate's 1st level cache / the persistence context. Hibernate will use them when it processes the result of the 2nd query.
@Query("SELECT m FROM MCValue m") // add WHERE clause as needed ...
@EntityGraph(attributePaths = {"selected"})
public List<MCValue> findAll();
然后,第二个查询获取Answer
实体,并使用EntityGraph
还获取关联的Value
实体.对于每个Value
实体,Hibernate将实例化特定的子类并检查一级缓存是否已包含该类和主键组合的对象.如果是这种情况,Hibernate将使用一级缓存中的对象,而不是查询返回的数据.
The 2nd query then fetches the Answer
entity and uses an EntityGraph
to also fetch the associated Value
entities. For each Value
entity, Hibernate will instantiate the specific subclass and check if the 1st level cache already contains an object for that class and primary key combination. If that's the case, Hibernate uses the object from the 1st level cache instead of the data returned by the query.
@Query("SELECT a FROM Answer a")
@EntityGraph(attributePaths = {"value"})
public List<Answer> findAll();
因为我们已经获取了所有具有关联的selected
实体的MCValue
实体,所以我们现在获得具有已初始化的value
关联的Answer
实体.并且,如果关联包含MCValue
实体,则其selected
关联也将被初始化.
Because we already fetched all MCValue
entities with the associated selected
entities, we now get Answer
entities with an initialized value
association. And if the association contains an MCValue
entity, its selected
association will also be initialized.
这篇关于JPA继承@EntityGraph包括子类的可选关联的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!