跳过孩子到父母的获取 - 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】:

为了避免循环引用的这个问题,我使用了 MapperMapStruct(请参阅 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 - 从孩子到父母

使用谓词在 Core Data 中获取父母的所有孩子

将孩子的属性应用到父母

Swift - CoreData NSPredicate - 获取父母的孩子

如何在 Spring Boot 中使用 Hibernate/JPA 返回多级 json