【发布时间】: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<Ingredient> ingredients ;。 -
我尝试过不初始化,即使不需要它,删除它也不能解决问题。