Часто нам приходится бороться с отношениями «один ко многим» и аналогичными отношениями в SQL и, в свою очередь, в Hibernate.
Когда мы выполняем запрос, в результате мы можем получить список с дублированными объектами, и это правильно, потому что SQL выполняет декартово продукт.
Пожалуйста, подумайте в этой ситуации:
Staff ID, NAME, SURNAME 1, Davide, Cerbo 2, Valentina, Perazzo Role ID, NAME, TITLE 1, Engineer 2, Chemist Responsibility ID, DESCRIPTION 1 Software development 2 Team management 3 Chemical Lab STAFF_ROLE STAFF_ID, ROLE_ID 1, 1 2, 2 ROLE_RESPONSIBILITY RESPONSIBILITY_ID, ROLE_ID 1, 1 2, 1 2, 2 3, 2
Если бы мы знали, что персонал отвечает за управление командой, мы могли бы объединиться, как показано ниже:
SetJoin<Staff, Role> roleJoin = root.join(Staff_.role); SetJoin<Role, Responsibility> responsibilityJoin = roleJoin.join(Role_.responsibility); Path<Long> id = responsibilityJoin.get(Responsibility.id); Predicate predicate = criteriaBuilder.equal(id, idValue);
Но для некоторых предметов у вас будет более одного объекта:
1, Davide, Cerbo 2, Valentina, Perazzo 1, Davide, Cerbo 2, Valentina, Perazzo
Как мы можем это исправить? Нам нужно выполнить подзапрос, и у нас есть два способа:
- с использованием предложения IN
SELECT * FROM staff WHERE id IN (SELECT staff_id FROM staff_role WHERE role_id IN (SELECT role_id FROM role_responsibility WHERE responsibility_id = 1));
- с использованием предложения EXISTS
SELECT * FROM staff WHERE exists(SELECT staff_id FROM staff_role, role_responsibility WHERE staff_role.staff_id = staff.id AND role_responsibility.role_id = staff_role.role_id AND role_responsibility.responsibility_id = 1)
И наконец, используя Hibernate, мы имеем:
Subquery<Long> subqueryResponsability = query.subquery(Long.class); Root<Role> rootSubquery = subqueryResponsability.from(Role.class); suqueryResponsability.select(rootSubquery.get(Role_.id)); SetJoin<Role, Responsibility> responsibilityJoin = rootSubquery.join(Role_.responsibility); SetJoin<Responsibility, Staff> staffJoin = rootSubquery.join(Role_.staff); subqueryResponsability.where( criteriaBuilder.equal(responsibilityJoin.get(Responsibility_.id), id), criteriaBuilder.equal(root.get(Staff_.id), staffJoin.get(Staff_.id))); Predicate predicate = criteriaBuilder.exists(subqueryResponsability);
Итак, в заключение:
1) Не используйте отдельный, у вас возникнут проблемы с обработкой разбивки на страницы.
2) Не используйте java.util.Set в качестве типа результата, это уловка. < br /> 3) Используйте внутренний запрос, я предполагаю, что существует, но также IN может быть решением.
4) Я знаю, что эта статья очень проста, но многие люди не понимают этой проблемы :)