Есть ли способ использовать имя столбца в качестве параметра в запросе, используя Spring Data JPA? - PullRequest
2 голосов
/ 19 января 2020

Я пишу приложение для визуализации данных статистики NBA. Я использую базу данных Spring Boot + MySql. Я пытаюсь найти наименьшее и наибольшее значение из каждого столбца с условием, что игрок должен был сыграть не менее 10 игр. Для этого я могу написать такие методы:

@Repository
public interface PerGameStatsRepository extends JpaRepository<PerGameStats, PerGameStatsId> {

@Query(value = "SELECT MAX(stats.pts) FROM PerGameStats stats WHERE stats.gamesPlayed >= 10")
        BigDecimal findMaxAmountOfPoints();

@Query(value = "SELECT MIN(stats.pts) FROM PerGameStats stats WHERE stats.gamesPlayed >= 10")
        BigDecimal findMinAmountOfPoints();
}

Однако в таблице около 15 столбцов, таких как «Точки», «Возвраты», «Ассисты», «Блоки» и т. Д. c. (И, возможно, я добавлю еще ). Чтобы получить минимальное и максимальное значения для каждого из них, я должен написать 2 метода для каждого столбца: 2x15 = 30 всего. Есть ли способ избежать этого повторения и написать метод, который принимает имя столбца в качестве параметра и на основании которого выполняет правильный запрос? Что-то вроде:

// this obviously doesn't work
@Query(value = "SELECT MAX(stats.:#{#fieldName}) FROM PerGameStats stats WHERE stats.gamesPlayed >= 10")
BigDecimal findMaxAmountOfField(String fieldName);

Ответы [ 2 ]

1 голос
/ 20 января 2020

Для этого случая вам нужно создать пользовательскую реализацию репозитория . Примерно так должно работать:

interface CustomizedPerGameStatsRepository {
  BigDecimal findMaxAmountOfField(String fieldName);
}

со следующей реализацией:

class CustomizedPerGameStatsRepositoryImpl implements CustomizedPerGameStatsRepository { // name has to be ...Impl

  private final EntityManager em;

  @Autowired
  public CustomizedPerGameStatsRepositoryImpl(JpaContext context) {
    this.em = context.getEntityManagerByManagedType(PerGameStats.class);
  }

  public BigDecimal findMaxAmountOfField(String fieldName) {
    return (BigDecimal) em.createQuery("SELECT MAX(" + fieldName + ") FROM PerGameStats stats WHERE stats.gamesPlayed >= 10")
      .getSingleResult();
  }
}

И изменение в вашем хранилище:

@Repository
public interface PerGameStatsRepository extends JpaRepository<PerGameStats, PerGameStatsId>, CustomizedPerGameStatsRepository {
}
0 голосов
/ 20 января 2020

Вы можете использовать Проекцию:

interface MinMaxProjection {

    BigDecimal getMin();
    BigDecimal getMax();

}

Тогда ваш репозиторий должен выглядеть примерно так:

@Query(value = "SELECT MIN(stats.pts) as min, MAX(stats.pts) as max FROM PerGameStats stats WHERE stats.gamesPlayed >= 10")
        MinMaxProjection findMinMaxAmountOfPoints();
}

Тогда ваш ответ должен быть:

{
max: 460,
min: 200,
}
...