【问题标题】:JPA and searching by several datesJPA 和按多个日期搜索
【发布时间】:2020-03-12 20:10:55
【问题描述】:

这是我的实体类

@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, OR plusOneDay, OR plusTwoWeek, etc 是否与今天匹配。如果匹配 - 它必须从数据库中获取。我可以这样写:

Set<Word> findAllByCreatedOrByPlusOneDayOrByPlusTwoDays(LocalDate date);

但是请求会太长,并且不起作用。 还有其他方法可以在一个日期之前检查多个字段吗?

【问题讨论】:

    标签: java spring spring-data-jpa spring-data jpql


    【解决方案1】:

    我认为您可以使用规范。文档: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); 
    

    【讨论】:

    • 检查用户的 id 怎么样?
    • 为什么要查看用户的id?我没看懂。
    • 因为每个单词都是由一个User映射的,所以你可以在我的代码中看到一个特殊的字段
    • 我明白了。您可以添加一个 AND word.user.user_id = :userId。像这样。
    【解决方案2】:

    是的,您可以传递可能的日期列表:

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

    然后调用它:

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

    【讨论】:

    • 我还必须检查其他日期字段,而不仅仅是创建日期
    • @MaksimRybalkin 但它们是从 created 字段计算的,对吗?这就是我将date.minusDays(1)date.minusDays(2) 传递到列表中的原因。
    • 每个日期都可以是今天的日期。我需要检查是否已创建或 plusOneDay、OR plusTwoWeek 等与今天的匹配。如果匹配 - 它必须从数据库中获取
    • @MaksimRybalkin 所以你需要检查created == datecreated.plusDays(1) == datecreated.plusDays(2) == date,也就是说created == datecreated == date.minusDays(1)created == datecreated == date.minusDays(2)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多