У меня есть две таблицы - user
и booking
.У каждого пользователя может быть много заказов (отношение один ко многим).
user: booking:
id | name | id | country | user_id | price |
-------------| ------------------------------------|
1 | Alice | 1 | Italy | 1 | 2000 |
2 | Bob | 2 | France | 1 | 2500 |
3 | Spain | 1 | 3000 |
Я хочу выбрать всех пользователей и все заказы, цена которых превышает 2000, используя Query DSL
.Если у пользователя нет заказов или заказы не соответствуют условию, я все еще хочу выбрать этого пользователя.
Во-первых, давайте посмотрим, как это будет выглядеть при использовании простого SQL-запроса на левое соединение:
SELECT u.*, b.* FROM user u LEFT JOIN booking b ON u.id = b.user_id AND b.price > 2000
Приведенный выше запрос должен дать следующий результат:
id | name | id | country | user_id | price |
-------------|----------------------------------------|
1 | Alice | 2 | France | 1 | 2500 |
1 | Alice | 3 | Spain | 1 | 3000 |
2 | Bob | null | null | null | null |
Теперь я хочу сделать это, используя JPA
с Query DSL
Связанные с JPA вещи:
@Entity
public class User {
@Id
private Long id;
private String name;
@OneToMany(cascade = ALL, fetch = EAGER, orphanRemoval = true, mappedBy = "user")
private List<Booking> bookings;
// getters and setters
}
@Entity
public class Booking {
@Id
private Long id;
private String name;
private Integer price;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "user_id")
private User user;
// getters and setters
}
Запрос DSL:
public List<User> getUsersAndBookings() {
QUser user = QUser.user;
QBooking booking = QBooking.booking;
JPAQuery<User> jpaQuery = new JPAQuery(entityManager);
List<User> result = jpaQuery.from(user).leftJoin(user.bookings, booking).on(booking.price.gt(2000)).fetchJoin().fetch();
return result;
}
На самом деле этот код не работает, и я получаю следующее исключение:
org.hibernate.hql.internal.ast.QuerySyntaxException: with-clause not allowed on fetched associations; use filters [select user from com.example.demo.entity.User user left join fetch user.bookings as booking with booking.price > ?1]
Проблема в том, что условие условие указано в on
метод -on(booking.price.gt(2000))
.
После некоторых исследований я обнаружил, что это условие должно быть указано в методе where
и должно выглядеть так:
List<User> result = jpaQuery.from(user).leftJoin(user.bookings, booking).where(booking.price.gt(2000)).fetchJoin().fetch();
Это работает, но не так, как я ожидал бы, что оно будет работать,поскольку он не возвращает ВСЕХ пользователей, он возвращает только одного пользователя (Алису), у которого есть несколько заказов, соответствующих условию условия.По сути, он просто фильтрует объединенную таблицу (таблицу результатов после операции левого соединения), и это не то, что я ищу.
Я хочу получить всех пользователей, и если нет никаких бронирований для конкретного пользователя, тогда просто укажите null
вместо списка бронирования для этого пользователя.
Пожалуйста, помогите, боролись в течение нескольких часов без какого-либо успеха.
Используемые версии:
- Spring Boot 2.0.2
- Spring Data JPA 2.0.7
- Hibernate 5.2.16.Final
- QueryDSL 4.1.4