Я создал приложение Spring Boot. Это REST-сервер. Поскольку службы REST используются клиентом Angular, с некоторой точки зрения, у меня довольно большой запрос, в котором у меня много LEFT и INNER JOIN для проверки дополнительных полей поиска.
К сожалению, все поля поиска являются необязательными, поэтому JOIN не всегда требуется. Сейчас я использую такой репозиторий:
@RestResource(exported = false)
@Transactional(readOnly = true)
// @formatter:off
@Query("SELECT t FROM Ticket t " + "JOIN Account a ON a.username=t.createdBy "
+ "LEFT JOIN User u ON u.account=a "
+ "LEFT JOIN Customer c ON t.customer=c " + "LEFT JOIN Account ca ON c.account=ca " + "JOIN t.checkPoint ck "
+ "LEFT JOIN t.customer c1 " + "LEFT JOIN t.transitCertificate tc " + "WHERE "
+ "(:allFieldsSearch IS NULL OR (t.code LIKE CONCAT('%',:allFieldsSearch,'%') OR t.licensePlate1 LIKE CONCAT('%',:allFieldsSearch,'%') OR t.licensePlate2 LIKE CONCAT('%',:allFieldsSearch,'%') OR c.name LIKE CONCAT('%',:allFieldsSearch,'%') )) "
+ "AND (:code IS NULL OR t.code LIKE CONCAT('%',:code,'%')) "
+ "AND (:licensePlate IS NULL OR (t.licensePlate1 LIKE CONCAT(:licensePlate,'%') OR t.licensePlate2 LIKE CONCAT(:licensePlate,'%'))) "
+ "AND (:transitCertificate IS NULL OR tc.code=:transitCertificate) "
+ "AND (:customer IS NULL OR c1.name LIKE CONCAT('%',:customer,'%')) "
+ "AND (:checkPoint IS NULL OR ck.name LIKE CONCAT('%',:checkPoint,'%')) "
+ "AND (:agent IS NULL OR (a.type='USER' AND u.name LIKE CONCAT('%',:agent,'%')) OR (a.type='CUSTOMER' AND c.name LIKE CONCAT('%',:agent,'%'))) "
+ "AND (:paid IS NULL OR t.paid=:paid) " + "AND (:ecommerce IS NULL OR (:ecommerce=true AND t.salesChannel='ECOMMERCE')) "
+ "AND (:checkedMedia IS NULL OR (:checkedMedia=false AND t.checkedMedia=false AND medias > 0)) "
+ "AND (:checkedLicensePlate IS NULL OR (:checkedLicensePlate=false AND t.checkedLicensePlate=false AND ((t.engineEuroLevel1>3 OR (t.engineEuroLevel1=3 AND t.particulateFilter1=true)) OR (t.engineEuroLevel2>3 OR (t.engineEuroLevel2=3 AND t.particulateFilter2=true)))) ) "
+ "AND (:warning IS NULL OR (warning=:warning)) "
+ "AND (:color IS NULL OR (color=:color)) "
+ "AND (:status IS NULL OR t.status=:status) "
+ "AND (:from IS NULL OR t.entryDate>=:from) "
+ "AND (:until IS NULL OR t.entryDate<=:until) "
+ "AND (:fromCreatedDate IS NULL OR t.createdDate>=:fromCreatedDate) "
+ "AND (:untilCreatedDate IS NULL OR t.createdDate<=:untilCreatedDate) "
// the customer cannot see canceled tickets
+ "AND (CAST(t.status as string) <>?#{hasRole('ROLE_CUSTOMER') ? 'CANCELED':''}) "
+ "AND (ca.username=?#{principal.username} OR t.createdBy LIKE ?#{hasRole('ROLE_CUSTOMER') ? principal.username:'%'})")
// @formatter:on
public Page<Ticket> search(@Param("allFieldsSearch") String allFieldsSearch, @Param("code") String code,
@Param("licensePlate") String licensePlate, @Param("transitCertificate") String transitCertificate,
@Param("customer") String customer, @Param("agent") String agent, @Param("checkPoint") String checkPoint,
@Param("paid") Boolean paid, @Param("ecommerce") Boolean ecommerce, @Param("checkedMedia") Boolean checkedMedia,
@Param("checkedLicensePlate") Boolean checkedLicensePlate, @Param("warning") Boolean warning, @Param("color") String color,
@Param("status") TicketStatus status, @Param("from") Instant from, @Param("until") Instant until,
@Param("fromCreatedDate") Instant fromCreatedDate, @Param("untilCreatedDate") Instant untilCreatedDate, Pageable pageable);
Код довольно удобный. Он компактен и больше ничего не нужно. К сожалению, здесь я выполняю все СОЕДИНЕНИЯ, даже если пользователь не устанавливает никаких параметров.
Мне было интересно, есть ли способ создать условное JOIN на основе наличия параметра.
Существуют различные варианты, которые могут удовлетворить все ваши требования: