Как создавать сложные запросы с критериями-API для объектов, унаследованных по типу соединения - PullRequest
0 голосов
/ 26 марта 2020

Я хочу получить все объекты через мой 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?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...