【问题标题】:JPA is eager loading FetchType.LAZY child collectionsJPA 急切地加载 FetchType.LAZY 子集合
【发布时间】:2013-07-28 00:00:06
【问题描述】:

我见过几个类似的问题,有 0 个很好的答案。

这应该很简单。我正在使用 Java JPA,我想有时但不是一直加载子实体列表。不幸的是,当我说懒惰地获取它时,JPA 似乎并没有在听我说话。我已经 100% 确定我的代码中没有任何地方可以以任何方式访问 childEntities 属性。但是,所有子实体仍然会在我的 JPA.em().find(..) 调用后立即加载。这就是我声明与注解的关系的方式。

@Entity
@Table(name = "parentEntities")
public class ParentEntity implements Serializable {
    ....
    @OneToMany(mappedBy = "entityPropertyName", fetch = FetchType.LAZY)
    public List<ChildEntity> childEntities;
    ...
}

这就是我加载父实体的方式:

ParentEntity parentEntity = JPA.em().find(ParentEntity.class, id);

此外,我希望有时急切地获取这个集合,并能够动态地告诉 JPA 何时这样做。不过,这是第 2 步。第 1 步只是为了让它正常工作。

【问题讨论】:

  • 您如何验证它是否已获取?是否可能设置了 orm.xml 或其他位置映射或实体侦听器来覆盖惰性设置或触发集合?您使用的是什么提供商?
  • 在调试器中,我可以在 find 调用后立即看到列表已填充。我没有使用任何 XML 进行配置,只有注释。
  • 现在我已经创建了一个非常臃肿和 hacky 的解决方案。我创建了两个父实体,一个带有子列表集合,一个没有。不幸的是,这种 hack(正如许多 hack 所做的那样)将污秽级联到我的其余代码中。
  • 您使用的是什么提供者,并且该实体之前是否已加载,因此关系可能已经被获取?在找到后尝试 em.refresh 并查看关系未触发,并确保您的调试器没有触发列表 - 它们类型的列表以及触发它的方式可能是特定的
  • JPA 是一个规范,而 hibernate、EclipseLink 等实现了该规范。您正在使用一个实现,而使用哪一个很重要。除了尝试刷新之外,您无需更改任何内容。如果它有效,那么我们知道您的提供程序支持惰性,并且正在发生诸如正在预加载的实体之类的事情。

标签: jpa lazy-loading


【解决方案1】:

我就是这样做的。请参考这个,它在那边也会很好地工作:

@Entity
@Table(name = "member_information")
    public class MemberInformation  implements Serilizable{

     @OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE},optional = false)
        private MemberInformationDetails memberInformationDetailsId;


     @LazyCollection(LazyCollectionOption.TRUE)
        @OneToMany(mappedBy = "memberInformationId", cascade = CascadeType.ALL)
        private Collection<AccountOpening> accountOpeningCollection;


    }

使用@OneToOne(fetch = FetchType.LAZY....) 进行一对一映射和集合使用@LazyCollection(LazyCollectionOption.TRUE)

@Entity
@Table(name = "member_info_details")
public class MemberInformationDetails implements Serializable{

@OneToOne(mappedBy = "memberInformationDetailsId")
    private MemberInformation memberInformationId;

.......//getter and setters

}


@Entity
@Table(name = "account_opening")
public class AccountOpening  implements Serializable {

 @JoinColumn(name = "member_information_id", referencedColumnName = "id", nullable = false)
    @ManyToOne(optional = false)
    private MemberInformation memberInformationId;

..........//getters and setters

}

当你想访问集合时,合并之前获取对象:

@Stateless
public class MemberInformationFacade{
..............
  public MemberInformation getMemberWithMemberDetails(MemberInformation m) {
        m = getEntityManager().merge(m);
        try {
            m.getMemberInformationDetailsId().getId();


            m.getMemberInformationDetailsId().accountOpeningCollection().size();

        } catch (Exception e) {
            e.printStackTrace();
        }
        return m;
    }

}

【讨论】:

  • 这周有空的时候我会试试这个。谢谢。
  • 你能告诉你为什么在 getMemberWithMemberDetails 中使用合并吗?
【解决方案2】:

我正在积极寻找您的问题 2 的答案:让 JPA 有时延迟加载内容,而有时则急切地加载。

至于您的#1 问题,在我看来您想要使用 getReference() 而不是 find()。如果您使用的是 Hibernate,那么它将创建对象的引用,然后仅在需要时才实际获取它。

我相信这会有所帮助: When to use EntityManager.find() vs EntityManager.getReference()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-19
    • 2010-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-06
    • 1970-01-01
    相关资源
    最近更新 更多