Reputation: 277
This is my entity class
@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);
}
As you see I have several LocalDate
fields.
I need to check, is created
, OR plusOneDay
, OR plusTwoWeek
, etc
matches with today's day. If it matches - it must be got from a database. I can write something like that:
Set<Word> findAllByCreatedOrByPlusOneDayOrByPlusTwoDays(LocalDate date);
But the request will be too long, and it doesn't work. Is there another way to check several fields by one date?
Upvotes: 0
Views: 756
Reputation: 427
I think that you may use Specification. Doc: https://docs.spring.io/spring-data/jpa/docs/1.7.0.RELEASE/reference/html/#specifications
I made some code, that may help.
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);
}
};
}
}
Repository Class:
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 {
}
Service class
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));
}
}
Edit:
Much easier, you may like:
@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);
Upvotes: 1
Reputation: 26026
Yes, you can pass a list of possible dates:
Set<Word> findAllByCreatedIn(List<LocalDate> dates);
and then invoke it as:
repo.findAllByCreatedIn(List.of(date, date.minusDays(1), date.minusDays(2)));
Upvotes: 1