gpt4 book ai didi

java - JPA 延迟获取列表调用 setter 中的 SELECT 查询

转载 作者:太空宇宙 更新时间:2023-11-04 13:07:40 24 4
gpt4 key购买 nike

有一种方法可以通过JPA从数据库返回实体。该实体具有其他实体的列表,获取类型为 LAZY。当我想将对象添加到此列表时,出现异常:

Caused by: Exception [EclipseLink-7242] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.ValidationException
Exception Description: An attempt was made to traverse a relationship using indirection that had a null Session. This often occurs when an entity with an uninstantiated LAZY relationship is serialized and that lazy relationship is traversed after serialization. To avoid this issue, instantiate the LAZY relationship prior to serialization.

因此,为了克服这个问题,我可以通过执行 .size() 来初始化此列表。在上面。问题是我真的不需要从数据库中获取这些对象,所以我想做这样的事情: fetchedEntity.setMyLazyFetchList(new ArrayList<>());效果很好。我可以进一步访问我的列表,但问题如下: set 方法调用与 fetchedEntity.getMyLazyFetchList().size() 相同的选择查询做。当我将值设置为新列表时,这些查询毫无用处,那么为什么要调用它们呢?

获取实体的方法

public Competitor findAndInitializeEmptyGroups(Integer idCompetitor) {
Competitor entity = em.find(Competitor.class, idCompetitor);
System.out.println("Before set ");
entity.setGroupCompetitorList(new ArrayList<>());
System.out.print("After set lazy list size ");
System.out.print(entity.getGroupCompetitorList().size());

return entity;
}

实体(竞争对手)中的延迟获取列表字段

@OneToMany(mappedBy = "idCompetitor")
private List<GroupCompetitor> groupCompetitorList = new ArrayList<>();

第二端关系字段(GroupCompetitor)

@JoinColumn(name = "id_competitor", referencedColumnName = "id_competitor")
@ManyToOne(optional = false)
private Competitor idCompetitor;

日志内容:

Info:   Before set
Fine: SELECT id_group_competitor, id_competitor, id_group_details FROM group_competitor WHERE (id_competitor = ?)
bind => [43]
Fine: SELECT id_group_details, end_date, start_date, version, id_competition, id_group_name FROM group_details WHERE (id_group_details = ?)
bind => [241]
...
many more SELECTs

Info: After set lazy list size
Info: 0

更换线路后

entity.setGroupCompetitorList(new ArrayList<>());

entity.getGroupCompetitorList().size();

和日志(除了列表现在由获取的实体组成之外,它们是相同的):

Info:   Before set
Fine: SELECT id_group_competitor, id_competitor, id_group_details FROM group_competitor WHERE (id_competitor = ?)
bind => [43]
Fine: SELECT id_group_details, end_date, start_date, version, id_competition, id_group_name FROM group_details WHERE (id_group_details = ?)
bind => [241]
...
many more SELECTs

Info: After set lazy list size
Info: 44

所以我的问题是:为什么SELECT当我执行 entity.setGroupCompetitorList(new ArrayList<>()); 时,会调用查询?出于性能原因我不需要它们。有什么方法可以消除这个问题或者到底是什么导致了这种行为?

使用:

  • EclipseLink JPA 2.1
  • 玻璃鱼4.1
  • Java 8

最佳答案

如果您想要添加元素并让 JPA 提供程序保留它,则不能不获取作为实体成员的列表。 JPA 提供者必须跟踪所有者、所有者并处理任何级联(我没有看到您已定义,但我怀疑级联选项的每种组合都有不同的代码路径)。最简单的方法是将列表存储在内存中,然后决定在提交/刷新时对数据库执行什么操作。

我相信您最初关于遍历 LAZY 的异常的原因是由于在托管上下文上访问外部。一旦您从 EJB 方法返回,您返回的实体就会分离。您必须将其重新附加到另一个 EntityManager 或确保在离开该方法之前已加载您要使用的所有惰性关系。调用 fetchedEntity.getMyLazyFetchList().size() 就是一个例子,并且在单个实体情况下工作得很好。如果您想在实体列表中强制加载 LAZY,我建议您阅读 LEFT JOIN FETCH 子句。我在这里假设您的 findAndInitializeEmptyGroups() 方法位于 EJB 中,从我看来像是在该方法中注入(inject)的 EntitManager em 来判断,并且这些方法将获得默认的 @TransactionAttribute(REQUIRED) 处理,因为我没有看到任何相反的注释。

现在,让我们回到最初的问题:

I want to add object to this list

您要解决的问题是将元素添加到列表中而不获取整个列表。您正在使用 mappedBy 属性,这意味着您已经创建了双向关系。如果 getGroupCompetitorList() 返回一个无序列表(Hibernate 中的“包”),那么您根本不必加载该列表。尝试这样的事情:

GroupCompetitorInteger idCompetitor 更改为 @ManyToOne(fetch=FetchType.LAZY) Competitor 竞争对手。相应地调整 getter 和 setter。

CompetitorgroupCompetitorList mappedBy更改为competitor。添加获取/设置方法。

然后您可以在 EJB 中使用如下方法从子端添加到列表:

public void addNewGroupCompetitorToCompetitor(Competitor comp, GroupCompetitor gComp) {
gComp.setCompetitor(comp);
em.persist(gComp);
em.flush();
}

下次您再次获取 Competitor 并遍历 entity.getGroupCompetitorList()(由 EntityManager 管理)时,它应该具有您添加的新 GroupCompetitor。这种事情会变得更加复杂,具体取决于 comp 是否是尚未持久化的新实体,但这就是基本思想。它可能需要一些调整才能与 EclipseLink 一起正常工作,但我对 Hibernate 进行了与 JPA 提供程序相同的操作,并且它可以工作。

关于java - JPA 延迟获取列表调用 setter 中的 SELECT 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34275836/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com