Spring Data JPA — фильтрация отношения @OneToMany отдельно

#java #spring-data-jpa

#java #spring-data-jpa

Вопрос:

Предположим, что следующее:

 public class Building {
   @Column(nullable = false)
   private String zipCode;

   @OneToMany(mappedBy = "building", fetch = FetchType.LAZY)
   private final Set<Contract> contracts = new HashSet<>();
}

public class Contract {
   @ManyToOne(optional = false, fetch = FetchType.EAGER)
   @JoinColumn(nullable = false, updatable = false)
   private Building building;


   @Column(nullable = false)
   private LocalDate activeFrom;
}
  

Используя предпочтительно репозитории spring-data-jpa, как я могу выбрать все здания с определенным zipCode , а затем для каждого здания, все контракты с более activeFrom ранним, чем X?

Все решения, которые я могу найти в Интернете, похоже, сосредоточены на фильтрации основного объекта ( Building ), тогда как я хотел бы использовать разные динамические критерии для дочернего объекта ( Contract ) и получать пустой список, если таковые не найдены. Я явно хочу получать здания без соответствующих контрактов.

Хорошо, если вместо классов сущностей используется DTO / projection.

Ответ №1:

Я исхожу из предположения, что вы ищете запрос JpaRepository, который вы могли бы использовать. Вы можете использовать «_» для применения запросов к полям во встроенных объектах.

Например, что-то вроде: findallbybuilding_zipcode и activefrombefore …

Комментарии:

1. Это отфильтровало Building бы s без a Contract , который активен до X. Я явно хочу, чтобы они возвращались с пустым списком в контрактах.

2. Хорошо, извините, я не понял этого из вопроса. Я понял это как контракт, являющийся основным объектом, который вы хотите вернуть, следовательно, будет пустым, если ничего не найдено.

3. Аналогично, не уверен, как это можно сделать в формате метода, но, возможно, стоит использовать @Query с выборками Join.

Ответ №2:

Вы можете использовать что-то подобное для фильтрации по почтовому индексу и activeFrom

 String FIND_ALL_BUILDINGS_BY_ZIP_CODE_AND_ACTIVE_FORM = "SELECT b FROM Building b"  
        " inner join b.contract as c "  
        " with c.activeFrom > :date "  
        " where b.zipCode = :zipCode";

@Query(FIND_ALL_BUILDINGS_BY_ZIP_CODE_AND_ACTIVE_FORM)
List<Group> findAllBuildingsByZipCodeAndActiveFrom(@Param("zipCode") String zipCode, @Param("date") LocalDate date);
  

Это даст вам пакет, который имеет по крайней мере один контракт, который активен с> даты

Также вы можете попробовать с этим запросом:

 String FIND_ALL_BUILDINGS_BY_ZIP_CODE_AND_ACTIVE_FORM = "SELECT b FROM Building b"  
        " inner join b.contract as c "  
        " where c.activeFrom > :date "  
        " and b.zipCode = :zipCode";
  

Просто убедитесь, что вы присоединились ко второй таблице перед фильтрацией

Комментарии:

1. This will give you a bulding that has atleast one contract that activeFrom > date Я боюсь, что в этом проблема — я явно хочу Buildings , чтобы соответствующие контракты тоже не возвращались.

2. чем добавлять больше условий с помощью ИЛИ