Условное соединение Spring Data JPA

Я создал приложение 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 на основе наличия параметра.

1
0
968
1

Ответы 1

Существуют различные варианты, которые могут удовлетворить все ваши требования:

Другие вопросы по теме