Объединение полей Entity через Spring Data

262
17 марта 2022, 09:20

Есть энтити объект

@Entity
@Table(name = "votes")
public class Vote extends AbstractBaseEntity implements Serializable {
    private static final long serialVersionUID = 1L;
    @JsonProperty(access = JsonProperty.Access.READ_ONLY)
    private LocalDate date = LocalDate.now();
    @JsonIgnore
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "restaurant_id", nullable = false)
    @OnDelete(action = OnDeleteAction.CASCADE)
    private Restaurant restaurant;
    @JsonIgnore
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id", nullable = false)
    private User user;
    public Vote() {
    }
    public Vote(User user, Restaurant restaurant) {
        this.user = user;
        this.restaurant = restaurant;
    }
    //getters and setters
}

Я использую Spring Data Repository, у меня уже есть метод для подсчета количества голосов по каждому ресторану

@Repository
public interface VoteRepository extends CrudRepository<Vote, Integer> {
    Integer countByRestaurantId(Integer restaurantId);
}

И сейчас я хочу добавить возможность просмотра статистики голосов по датам. Как вариант - я могу передавать Map <LocalDate, Integer>, где значение - количество голосов по дате(ключу):

@RestController
@RequestMapping(value = ADMIN_VOTES_URL, produces = JSON_TYPE)
public class AdminVoteController implements Controller {
    private final Logger log = LoggerFactory.getLogger(getClass());
    @Autowired
    private VoteService voteService;
    @GetMapping("/statistics")
    public Map<LocalDate, Integer> getVoteStatistics(@PathVariable Integer restaurantId) {
        log.info("get count of the votes for restaurant {}", restaurantId);
        return voteService.getVoteStatistic(restaurantId);
    }
}

Моя неудавшаяся попытка обратиться в репозиторий выглядит так:

@Query("select distinct v.date, count(v.id) from Vote v where v.restaurant.id = ?1 group by v.date")
    Map<LocalDate, Integer> findAllByDateAndRestaurantId(Integer restaurantId);

Как мне это сделать при помощи Spring Data? Либо если можно как-то по-другому - буду рад любому совету, спасибо!

Answer 1

Создайте кастомный репозиторий

public interface StatisticVotesRepository {
     Map<LocalDate, Integer> findAllByDateAndRestaurantId(Integer restaurantId);
}

Создаете его реализацию

public class StatisticVotesRepositoryImpl implements StatisticVotesRepository {
private EntityManager entityManager;
@Autowired
public StatisticVotesRepositoryImpl(EntityManager entityManager) {
    this.entityManager = entityManager;
}
@Override
public Map<LocalDate, Integer> findAllByDateAndRestaurantId(Integer restaurantId) {
    ...
    entityManager.createNativeQuery(
       "select distinct v.date, count(v.id) from Vote v where v.restaurant.id = :pRestaurantId group by v.date")
                 .setParameter("pRestaurantId", restaurantId);
    ...
}
}

наследуете его вашим репозиторием

@Repository
public interface VoteRepository extends CrudRepository<Vote, Integer>, StatisticVotesRepository {
    Integer countByRestaurantId(Integer restaurantId);
}

и добавьте новый репозиторий в конфигурацию в аннотацию @EnableJpaRepositories, например так

@EnableJpaRepositories(basePackages = "youPackage", repositoryImplementationPostfix = "RepositoryImpl") 
Answer 2

На самом деле - нашлось более простое решение.

1) Создал ДТО:

public class VoteTo implements Serializable {
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate date;
    private Long count;
    public VoteTo() {
    }
    public LocalDate getDate() {
        return date;
    }
    public void setDate(LocalDate date) {
        this.date = date;
    }
    public Long getCount() {
        return count;
    }
    public void setCount(Long count) {
        this.count = count;
    }
    public VoteTo(LocalDate date, Long count) {
        this.date = date;
        this.count = count;
    }
}

2) Создал в том же репозитории метод, прямо обращающийся к конструктору:

@Query("select new ru.topjava.graduation.model.dto.VoteTo(v.date, count(v.id)) from Vote v " +
" where v.restaurant.id = ?1 group by v.date")
List<VoteTo> groupCountByData(Integer restaurantId);
READ ALSO
Веб сервер Java

Веб сервер Java

Имеется Java сервер на HerokuПолучает запрос и должен вернуть некую строку, по сути Json

160
java swing как добавить boxlayout

java swing как добавить boxlayout

пишу программу которая рассчитает сопротивление резисторов подключенных параллельно

221