【问题标题】:JSF, CDI, EJB + JPA and TransactionJSF、CDI、EJB + JPA 和事务
【发布时间】:2014-06-05 13:51:03
【问题描述】:

在使用 JSF、CDI、EJB + JPA 进行 JEE 7 设置时,我遇到了“无法延迟初始化集合”的问题。我找到了解决方案,但想确认它是正确的解决方案,并且我正确理解了问题。

设置基本上是:

JSF -> CDI Bean -> EJB3 -> JPA

在 JSF 页面中我基本上是这样做的:

<ui:repeat value="#{dishService.dishes}" var="dish">
    <ui:repeat value="#{dish.ingredients}" var="ingredient">
        #{ingredient.name}
    </ui:repeat>
</ui:repeat>

CDI Bean:

@Dependent
@Named
public class DishService {

    @Inject
    private DatabaseServiceLocal databaseService;

    public List<Dish> getDishes() {
        return databaseService.getDishes();
    }

}

EJB:

@Stateless
public class DatabaseService implements DatabaseServiceLocal, DatabaseServiceRemote {

    @PersistenceContext(unitName = "dishlist")
    private EntityManager entityManager;

    public List<Dish> getDishes() {
        final Query query = entityManager.createQuery("SELECT d FROM Dish d");
        return query.getResultList();
    }
}

JPA 实体 Dish:

@OneToMany(mappedBy = "dish", 
           cascade = CascadeType.PERSIST, 
           orphanRemoval = true)
private List<Ingredient> ingredients = Collections.emptyList();

和成分:

@ManyToOne
private Dish dish;

运行它会产生错误:

无法延迟初始化角色集合:entity.Dish.ingredients,无法初始化代理 - 无会话

据我了解,这是因为 JTA 容器管理的事务在 EJB 的公共方法 getDishes() 完成时结束。 JPA 实体被分离,会话关闭,无法再延迟加载 JSF 页面中的成分。

经过一些研究,似乎最普遍接受的解决方案是JOIN FETCH。所以我将我的 JPA 查询更改为

entityManager.createQuery("SELECT DISTINCT d from Dish d JOIN FETCH d.ingredients");

问题就解决了。我必须添加DISTINCT,因为没有它,查询会生成所有菜肴和配料的笛卡尔积,我想这是预期的。

所以最后的问题是:我是否正确理解了这个问题,JOIN FETCH 是正确的解决方案吗?

【问题讨论】:

  • 我认为只需删除持久层中的初始化即可工作:private List&lt;Ingredient&gt; ingredients ;。
  • 我尝试过不初始化,即使不需要它,删除它也不能解决问题。

标签: jsf jpa ejb cdi


【解决方案1】:

是的,在查询上设置 join fetch 是最合适的方式。

您还可以使用实体图,这是 JPA 2.1 中的一项新功能来进行提取。

发生这种情况的原因是事务在您的 CDI 托管 bean 中开始。 JSF 将调用托管 bean,但它周围有几个包装器。它正在尝试获取事务之外的值。

【讨论】:

    【解决方案2】:

    对于@Many 类型的关系,默认FetchType 是LAZY,这意味着List&lt;Ingredient&gt; 在第一次访问之前不会被加载。

    FetchType fetch (可选)关联是否应该是惰性的 已加载或必须急切获取。 EAGER 策略是一项要求 在关联实体必须的持久性提供程序运行时 被热切地取走。 LAZY 策略是对持久性的暗示 提供程序运行时。

    默认值:javax.persistence.FetchType.LAZY

    自:JPA 1.0

    是的,对于您的情况,JOIN FETCH 解决方案看起来不错。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-17
      • 1970-01-01
      • 2012-02-12
      • 1970-01-01
      • 2015-08-18
      • 1970-01-01
      • 2015-08-04
      • 2012-01-19
      相关资源
      最近更新 更多