【问题标题】:LazyInitializationException when loading entity children with FetchType.LAZY使用 FetchType.LAZY 加载实体子项时出现 LazyInitializationException
【发布时间】:2015-07-31 23:51:38
【问题描述】:

当我的JSF 视图请求一个实体的子级列表时,我得到一个LazyInitializationException。我没有直接使用Hibernate,而是JPA。 CHILD DB 表在 PARENT 表上有一个 FK。这是一种非常标准的关系。

以下是相关代码摘录的样子:

家长

@Entity
@Table(name="PARENT")
@NamedQueries({@NamedQuery(name = "Parent.getByID", 
            query = "SELECT i FROM Parent i WHERE i.parentID = :parentID")})
public class Parent implements Serializable {

    @Id
    @SequenceGenerator(name="PARENT_SEQ_GEN", sequenceName="DB_SEQ", allocationSize = 1)
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="PARENT_SEQ_GEN")
    @Column(name="PARENT_ID")
    private long parentID;

    /* other stuff */

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "parent", fetch = FetchType.LAZY)
    private List<Child> childList;

    /* other stuff */

    public List<Child> getChildren() {
        return this.childList;
    }

儿童

@Entity
@Table(name="CHILD")
@NamedQueries({@NamedQuery(name = "Child.getByID", 
            query = "SELECT i FROM Child i WHERE i.childID = :childID")})

public class Child implements Serializable {

    @Id
    @SequenceGenerator(name="CHILD_SEQ_GEN", sequenceName="DB_SEQ", allocationSize = 1)
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="CHILD_SEQ_GEN")
    @Column(name="CHILD_ID")
    private long childID;

    @JoinColumn(name = "PARENT_ID", referencedColumnName = "PARENT_ID", insertable = true, updatable = false)
    @ManyToOne(optional = false)
    private Parent parent;

查看

<h:dataTable id="childTbl" value="#{parent.children}" 
        var="child" width="100%"
        styleClass="data" border="1" cellpadding="2"
        cellspacing="0">
    <h:column>
        <f:facet name="header">Child Name</f:facet>
        #{child.name}
    </h:column>
    <h:column>
        <f:facet name="header">DOB</f:facet>
        #{child.dob}
    </h:column>
</h:dataTable>

如果我将 FetchType 更改为 EAGER,我不会收到异常,但我希望数据获取是惰性的,即仅按需获取。为了避免这种异常,我需要进行哪些更改?

可能相关

在视图中,当FetchTypeEAGER 时,它确实成功呈现,我有一个为每个父级添加一个子级的表单,一旦添加了一个子级,我尝试使用f:ajax 刷新子列表自动列出:

<h:commandButton value="Add Child" action="#{parentBean.addChild}">
    <f:ajax execute="@form" render="childTbl"/>
</h:commandButton>

但是,即使相应的数据库事务成功,当我在 AJAX 上添加子表时(我这样做是为了避免重新加载页面),由于子表没有用新行更新,刷新失败。仅当我通过重新加载页面在浏览器中刷新视图时,新添加的子项才在表中可见。

但是,请注意LazyInitializationException 出现在我第一次尝试加载包含父母及其子女的页面时,而FetchTypeLAZY。它与刷新失败没有直接关系,当FetchTypeEAGER 时会发生这种情况。但我认为我的代码中可能存在一些根本性缺陷,修复后会启用延迟初始化和 AJAX 视图刷新。

【问题讨论】:

  • 交易完成后是否刷新父实体?
  • 是的,&lt;f:ajax execute="@form" render="childTbl"/&gt; 应该这样做
  • 你可以看到这个答案,同样的问题,但与 jsp 页面 [链接] [1] [1]:stackoverflow.com/questions/19047835/…
  • 这是因为您试图在此 EL #{parent.children} 中引用延迟初始化的集合。我假设 EL 指的是 private List&lt;Child&gt; childListgetChildren()Parent 实体中返回。这与 JSF 没有任何关系。根据功能要求或项目的结构/流程,使用单独的查询根据其父行检索子级列表。

标签: hibernate jsf jpa lazy-loading


【解决方案1】:

因为您为 childList 列定义了 FetchType.LAZY 提取;看看 FetchType.LAZY 和 FetchType.EAGER 与 HERE 的区别。如果你想得到不为 null 的 childList 对象,有 2 个选项:

  1. 将 FetchType.LAZY 更改为 FetchType.EAGER
  2. 当您的 Child 对象在 @Transaction 注释方法中持久调用 getChildren() 时。

【讨论】:

    猜你喜欢
    • 2012-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多