Я хочу получить все объекты через мой AController
с некоторыми условиями.
Например, я хочу получить все объекты типа B, C, D. Но для типа B только тот, где parent is null
.
Работает в request1
с настраиваемым JPQL-запросом, но с critertia-api в request2
не работает. Я получаю только объекты типа B. Отсутствуют типы C и D.
Я хочу использовать critera-api для построения более сложных запросов, таких как request3, или добавить некоторые другие параметры.
Я пытался самостоятельно объединить таблицы с помощью критерия-API, но это не представляется возможным при объединенной стратегии наследования.
Мой код выглядит следующим образом:
Объекты:
@Inheritance(strategy = InheritanceType.JOINED)
@Entity
public class A {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
long id;
String name;
}
@Entity
public class B extends A {
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "parent_id")
private B parent;
}
@Entity
public class C extends A {
String propC;
}
@Entity
public class D extends A {
String propD;
}
Репозиторий:
public interface ARepository extends JpaRepository<A, Long>, JpaSpecificationExecutor<A> {
@Query("select A from A left join B on A.id = B.id where B.parent is null")
Page<A> getAllOnlyTopLevel(Pageable pageable);
}
Контроллер:
@RequestMapping("/a")
public class AController {
public static Specification<A> isTopLevel() {
return (Specification<A>) (root, query, criteriaBuilder) -> {
Root<B> bRoot = criteriaBuilder.treat(root, B.class);
return criteriaBuilder.isNull(bRoot.get(B_.PARENT));
};
}
public static Specification<A> search(String keyword) {
return (Specification<A>) (root, query, criteriaBuilder) -> {
if (keyword.isEmpty()) return criteriaBuilder.conjunction();
else return criteriaBuilder.like(root.get(A_.NAME, keyword));
};
}
@Autowired
ARepository aRepository;
@GetMapping("1")
Page<A> request1(Pageable pageable) {
return aRepository.getAllOnlyTopLevel(pageable);
}
@GetMapping("2")
Page<A> request2(Pageable pageable) {
return aRepository.findAll(isTopLevel(), pageable);
}
@GetMapping("3")
Page<A> request3(Pageable pageable, String keyword) {
return aRepository.findAll(isTopLevel().and(search(keyword)), pageable);
}
}
Я думаю, что одной из проблем является то, что hibernate строит запросы для API-критериев с inner join
. Для request2
выполненный sql выглядит следующим образом:
... from A inner join B ... left outer join C ... left outer join D ...
where B.parent_id is null
Можно ли предотвратить переход в спящий режим, используя внутреннее соединение для критерия-API?