跳过孩子到父母的获取 - JPA
Posted
技术标签:
【中文标题】跳过孩子到父母的获取 - JPA【英文标题】:Skip child to fetching of parent - JPA 【发布时间】:2017-10-25 00:02:46 【问题描述】:我面临一个问题,即数据被递归提取。我想避免孩子获取父数据。这导致了递归问题。 我已经提到了下面的代码
Pojo 结构
class Parent
..
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private List<Child> childs;
..
class Child
..
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parentId")
private Parent parent;
..
像这样获取数据
` em = EMF.get().createEntityManager();
Query q = em.createQuery("Select p from Parent p", Parent.class);
List<Parent> parents = q.getResultList();
// Till this point all looks good but when the code gets executed
parent.getChilds();
`
它正在获取这样的数据:
Parent
child1
Parent
child2
Parent
child2
Parent
..
..
child2
..
我不需要,我只想要这样的数据:
Parent1
child1
child2
Parent2
child1
child2
child3
【问题讨论】:
默认获取模式是惰性的 @soorapadman 默认情况下,对多对关系的获取是惰性的,对一对一关系是渴望的 什么供应商? OneToOne/ManyToOne 的延迟获取是特定于提供商的,并且可能需要更多内容,具体取决于您的环境。例如 EclipseLink 需要编织 eclipse.org/eclipselink/documentation/2.5/concepts/… 【参考方案1】:为了避免循环引用的这个问题,我使用了 Mapper 和 MapStruct(请参阅 official documentation 进行快速设置):
然后我可以轻松地编写一个映射器来忽略这样的属性:
public interface SecondaryObjectMapper
@Mapping(target = "primaryObject.secondaries", ignore=true),
SecondaryObjectDto toSecondaryObjectDto(SecondaryObject source);
并像这样使用它:
repository.findAll(pageable).map(secondaryObjectMapper::toSecondaryObjectDto)
【讨论】:
【参考方案2】:为了避免这个问题,请在下面声明父子getter方法
@JsonBackReference
public Parent getParent()
return parent;
@JsonManagedReference
public List<Child> getChilds()
return childs;
【讨论】:
您可能还想多描述一下为什么这可以解决问题中的问题,而不仅仅是粘贴一些代码。 :)【参考方案3】:它将作为大量数据的无限循环。最佳做法是在子类列中提及 @JsonIgnore。 稍后谢谢我
【讨论】:
【参考方案4】:虽然FetchType.EAGER
是一个合约,FetchType.LAZY
只是一个提示,因为延迟获取并不总是可能的。这可能取决于例如在您使用的 JPA 提供程序及其配置上。延迟获取对于一对一关系尤其成问题。
如果每个Child
都有一个Parent
,请尝试将optional=false
添加到您的@ManyToOne
。这可能启用延迟获取。
由于Parent
实体已加载到持久性上下文中,填充Children.parent
不应触发对数据库的查询。你真的看到正在执行的查询吗?你怎么知道Children.parent
正在加载?如果您正在访问该值以检查该事实,那么您很可能实际上是在自己触发按需加载。
【讨论】:
如果每个孩子都有一个父母,请尝试将 optional=false 添加到您的@ManyToOne。这可能会启用延迟获取。它没有工作 你怎么知道 Children.parent 正在加载?我需要执行 parent.getChilds();当我这样做时,我可以在其中看到父对象,并且在这个父对象中还有一个子对象,依此类推。您可以通过以下方式获得一个想法:drive.google.com/file/d/0B_A6oOU92Jt8M2pGZlpaQ3RuQTA/… 好的。正如我所说,这不是性能问题,因为Parent
实体已经存在于持久化上下文中,所以Parent
对子项的查找不会命中数据库。如果您仍然想要延迟加载,您是在 Java SE 还是 Java EE 中使用 JPA?为了使延迟加载与一对一关系一起工作,您需要启用编织(请参阅:eclipse.org/eclipselink/documentation/2.6/concepts/… 及其上方的段落)
我们拥有 Java EE 和 EclipseLink,版本:Eclipse Persistence Services - 2.0.2.v20100323-r6872。是的,它不是性能,但应用程序正在挂起。原因是,因为它是双向关系,当我们获取孩子时,它也会获取父母,这再次设置了孩子在其中有一个父母。这导致服务器挂起,因为循环值。
我不确定单独的 EclipseLink 是否会导致无限循环,因为对于相当常见的用例来说,这将是一个严重的错误。您确定parent.getChilds()
是问题的根源吗?你能在堆栈跟踪中看到其他方法吗(我知道你最终会得到一个***Error
)?您设法使用调试器检查了Parent.getChilds()
的值这一事实表明加载子项已成功完成,并且该错误是由稍后执行的一些其他代码引起的......
没有 ***Error 或任何其他异常。问题是它需要超过 1 分钟的时间,这导致我们的服务器超时。我们需要在一分钟内得到结果。如果我们增加服务器超时时间,它将正常工作。以上是关于跳过孩子到父母的获取 - JPA的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 JPA/Hibernate 在孩子的 id 中引用父母的 id?
获取 parent.location.url - iframe - 从孩子到父母