С настройкой JEE 7 с использованием JSF, CDI, EJB + JPA Я столкнулся с проблемой «не удалось лениво инициализировать коллекцию». Я нашел решение, но хотел бы подтвердить, что это правильное решение и что я правильно понял проблему.JSF, CDI, EJB + JPA и транзакция
Установка в основном это:
JSF -> КДИ Bean -> EJB3 -> JPA
На странице JSF я в принципе:
<ui:repeat value="#{dishService.dishes}" var="dish">
<ui:repeat value="#{dish.ingredients}" var="ingredient">
#{ingredient.name}
</ui:repeat>
</ui:repeat>
КДИ 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 сущность Блюдо:
@OneToMany(mappedBy = "dish",
cascade = CascadeType.PERSIST,
orphanRemoval = true)
private List<Ingredient> ingredients = Collections.emptyList();
и Ингредиент:
@ManyToOne
private Dish dish;
Запуск этого производит ошибку:
не удалось инициализировать лениво коллекцию роли: entity.Dish .ingredients, не удалось инициализировать прокси - нет Сессия
Насколько я понимаю, это происходит потому, что транзакция, управляемая контейнером JTA, завершается, когда завершается открытый метод getDishes()
EJB. Субъекты JPA отделяются и сеанс закрывается, и уже невозможно более лениво загружать компоненты на странице JSF.
После некоторых исследований казалось, что наиболее распространенным решением для этого является JOIN FETCH
. Поэтому я изменил свой запрос JPA на
entityManager.createQuery("SELECT DISTINCT d from Dish d JOIN FETCH d.ingredients");
И проблема решена. Я должен был добавить DISTINCT
, так как без него запрос производит декартово произведение всех блюд и ингредиентов, ожидаемого, я полагаю.
Итак, наконец, вопрос: правильно ли я понял проблему и JOIN FETCH
правильное решение?
Я думаю, что это может сработать, просто удалив инициализацию в слое persistence: 'private List components;'. –
Omar
Я пробовал без инициализации, и хотя он не нужен, удаление его не решает проблему. –