Почему QueryDSL или HQL изменяют условие ON на WITH?

  • Я использую библиотеку QueryDSL
  • Версия Hibernate 5.4.33
  • БД PostgreSQL

Есть два класса сущностей, связанных отношением @OneToMany (опускаю очевидные аннотации Lombok, генераторов ключей и т.д., чтобы не писать лишнего)

@Entity
@Table(name = "products")
public class Product {
    
    @Id
    private UUID guid;
    
    //Название продукта
    private String name;
    
    //используется ли продукт
    private Boolean used;

    @OneToMany //fetchType lazy по умолчанию
    @JoinColumn(name = "product_guid")
    private List<Link> links = new ArrayList<>();

    //доп. поля....
}

@Entity
@Table(name = "link")
public class Link {

    @Id
    private UUID guid;

    @Column(name = "product_guid")
    private UUID productGuid;
    
    //канал ссылки (WEB/MOBILE)
    private Channel channel;

    //доп. поля....
}

Для составления запросов используется JpaQueryFactory из библиотеки query-dsl-jpa.

@Bean
public JPAQueryFactory jpaQueryFactory(@Autowired EntityManager em) {
    return new JPAQueryFactory(JPQLTemplates.DEFAULT, em);
}

Далее реализация репозитория продуктов, BaseRepositoryImpl имеет поля QProduct.product, QLink.link.

@Repository
public class ProductRepositoryImpl extends BaseRepositoryImpl<Product, UUID> implements ProductRepository {
    public ProductRepositoryImpl(EntityManager em,
                                 JPAQueryFactory jpaQueryFactory) {
        super(Product.class, em, jpaQueryFactory, QProduct.product);
    }
    
    //Проблемный запрос
    @Override
    public List<Product> findAllProductsWithLinks(@NotNull List<String> names, Channel channel) {
        Predicate predicate =
                product.name.in(names)
                .and(product.used.isTrue())
                .and(link.channel.isNull()
                        .or(link.channel.eq(channel))
                );
        return queryFactory
                .select(product)
                .from(product)
                .where(predicate)
                .leftJoin(product.links, link)
                .on(link.channel.eq(channel))
                .fetchJoin()
                .distinct()
                .fetch();
    }
}

Хотелось бы одним запросом без ленивой подгрузки вытащить записи продуктов и связанных с ними линками, при этом продукты, у которых отсутствуют линки по условию соединения таблиц ON l.channel = ? так же должны приходить. Но при выполнении запроса получаю ошибку: Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: with-clause not allowed on fetched associations;

Перерыв поисковики я нашел более менее подходящий совет:
https://github.com/querydsl/querydsl/pull/2604 - подставить в конструктор JpaQueryFactory JPQLTemplates.DEFAUL, так как в этом классе метод public boolean isWithForOn() возвращает false . Но это не помогло. Я проходился дебагом до использования метода isWithForOn(), querydsl формирует запрос с условием ON, но где-то в недрах hibernate видимо происходит замена ON на WITH.

Хотелось бы понять, почему именно это происходит? Можно ли это как-то исправить, или подойдет реализация только с ленивой подгрузкой? Изменять fetchType на EAGER для линков тоже не нужно, так как где-то есть запросы, где они вообще не используются.

Спасибо!


Ответы (0 шт):