使用JSF,CDI,EJB + JPA进行JEE 7设置时遇到了“未能懒惰地初始化集合”的问题。我找到了一个解决方案,但想确认这是一个合适的解决方案,并且我正确地理解了这个问题。JSF,CDI,EJB + JPA和事务处理
的设置主要是:
JSF - > CDI豆 - > EJB3 - > JPA
在JSF页面我基本上做到:
<ui:repeat value="#{dishService.dishes}" var="dish">
<ui:repeat value="#{dish.ingredients}" var="ingredient">
#{ingredient.name}
</ui:repeat>
</ui:repeat>
的CDI豆:
@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的实体碟:
@OneToMany(mappedBy = "dish",
cascade = CascadeType.PERSIST,
orphanRemoval = true)
private List<Ingredient> ingredients = Collections.emptyList();
和配料:
@ManyToOne
private Dish dish;
运行此产生错误:
未能懒洋洋地初始化角色的集合:entity.Dish .reredients,无法初始化代理 - 无会话
据我了解,这是因为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 ingredients;'。 –
Omar
我尝试了没有初始化,即使它不需要,删除它并不能解决问题。 –