JPA и поиск по нескольким датам - PullRequest
0 голосов
/ 12 марта 2020

Это мой класс сущностей

@Data
@NoArgsConstructor
@Builder
@AllArgsConstructor
@Entity(name = "words")
public class Word {

    @Id
    private Long id;

    @ManyToOne
    private Group group;

    @ManyToOne
    private User user;

    @NotBlank
    private String englishWord;

    @NotBlank
    private String russianWord;

    private LocalDate created = LocalDate.now();

    private final LocalDate plusOneDay = created.plusDays(1);

    private final LocalDate plusTwoDays = created.plusDays(2);

    private final LocalDate plusFiveDays = created.plusDays(5);

    private final LocalDate plusTenDays = created.plusDays(10);

    private final LocalDate plusTwoWeeks = created.plusWeeks(2);

    private final LocalDate plusSixWeeks = created.plusWeeks(6);

    private final LocalDate plusThreeMonths = created.plusMonths(3);

    private final LocalDate plusSixMonths = created.plusMonths(6);

    private final LocalDate plusOneYear = created.plusYears(1);
}

Как видите, у меня есть несколько полей LocalDate.

Мне нужно проверить, совпадает ли created, ИЛИ plusOneDay, ИЛИ plusTwoWeek, etc с сегодняшним днем. Если это соответствует - это должно быть получено из базы данных. Я могу написать что-то вроде этого:

Set<Word> findAllByCreatedOrByPlusOneDayOrByPlusTwoDays(LocalDate date);

Но запрос будет слишком длинным, и он не будет работать. Есть ли другой способ проверить несколько полей к одной дате?

Ответы [ 2 ]

1 голос
/ 12 марта 2020

Я думаю, что вы можете использовать спецификацию. Do c: https://docs.spring.io/spring-data/jpa/docs/1.7.0.RELEASE/reference/html/#specifications

Я сделал некоторый код, который может помочь.

import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.time.LocalDate;

public class WordSpecs {

        public static Specification<Word> isOneDateEqual(final LocalDate date){
            return new Specification<Word>() {
                @Override
                public Predicate toPredicate(Root<Word> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                    final Predicate created = criteriaBuilder.equal(root.get("created"), date);
                    final Predicate plusOneDay = criteriaBuilder.equal(root.get("plusOneDay"), date);
                    return criteriaBuilder.or(created, plusOneDay);
                }
            };

        }
    }

Класс репозитория:

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

@org.springframework.stereotype.Repository
public interface WordRepository extends JpaRepository<Word, Long>, JpaSpecificationExecutor {


}

Класс обслуживания

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.List;

@Service
public class WordService {

    @Autowired
    private WordRepository repository;

    public List<Word> findMatched(final LocalDate date){
        return repository.findAll(WordSpecs.isOneDateEqual(date));

    }

}

Редактировать:

Гораздо проще, вам может понравиться:

@Query("SELECT word FROM Word word WHERE 1 = 1 AND word.user.userId = :userId AND ( word.created = :date OR word.plus1 = :date ) " )
List<Word> findMatched(@Param("date") final LocalDate date, @Param("userId") final Long userId); 
1 голос
/ 12 марта 2020

Да, вы можете передать список возможных дат:

Set<Word> findAllByCreatedIn(List<LocalDate> dates);

и затем вызвать его как:

repo.findAllByCreatedIn(List.of(date, date.minusDays(1), date.minusDays(2)));
...