在我的应用程序中,我使用
Spring Data和hibernate作为JPA提供程序来持久化和读取数据.
我有顶级实体类:
@Entity @Getter @Setter @Table(name = "operation") @Inheritance(strategy = InheritanceType.JOINED) @EqualsAndHashCode(of = {"operationId"}) public abstract class Operation implements Serializable { public static final int OPERATION_ID_LENGTH = 20; @Id @Column(name = "operation_id",length = OPERATION_ID_LENGTH,nullable = false,columnDefinition = "char") private String operationId; @Column(name = "operation_type_code") @Getter(AccessLevel.NONE) @Setter(AccessLevel.NONE) private String operationTypeCode; @Temporal(TemporalType.TIMESTAMP) @Column(name = "begin_timestamp",nullable = false) private Date beginTimestamp = new Date(); @Temporal(TemporalType.TIMESTAMP) @Column(name = "end_timestamp") private Date endTimestamp; @Column(name = "operation_number",length = 6,columnDefinition = "char") private String operationNumber; @Enumerated(EnumType.STRING) @Column(name = "operation_status",length = 32,nullable = false) private OperationStatus status; @ManyToOne(optional = false) @JoinColumn(name = "user_id") private User user; @ManyToOne @JoinColumn(name = "terminal_id") private Terminal terminal; @Column(name = "training_mode",nullable = false) private boolean trainingMode; }
对于继承的类,我有相应的存储库:
public interface ConcreteOperationRepository extends JpaRepository<ConcreteOperation,String> { @Query("SELECT o FROM ConcreteOperation o WHERE o.beginTimestamp BETWEEN :from AND :to AND o.status = :status AND o.terminal.deviceId = :deviceId AND o.trainingMode = :trainingMode") Collection<ConcreteOperation> findOperations(@Param("from") Date startDay,@Param("to") Date endDay,@Param("status") OperationStatus status,@Param("deviceId") String deviceId,@Param("trainingMode") boolean trainingMode); }
我用以下方法进行集成测试:
@Transactional @Test public void shouldFindOperationByPeriodAndStatusAndWorkstationId() { Date from = new Date(Calendar.getInstance().getTime().getTime()); List<String> terminalIds = loadTerminalIds(); List<OperationStatus> typeForUse = Arrays.asList(OperationStatus.COMPLETED,OperationStatus.LOCKED,OperationStatus.OPEN); int countRowsForEachType = 3; int id = 100001; for (String terminalId : terminalIds) { for (OperationStatus status : typeForUse) { for (int i = 0; i < countRowsForEachType; i++) { concreteOperationRepository.save(createConcreteOperation(status,terminalId,String.valueOf(++id))); } } } Date to = new Date(Calendar.getInstance().getTime().getTime()); for (String terminalId : terminalIds) { for (OperationStatus status : typeForUse) { Collection<ConcreteOperation> operations = concreteOperationRepository.findOperations(from,to,status,false); assertEquals(countRowsForEachType,operations.size()); } } }
但是由于结果为空而我使用MysqL数据库时此测试失败(但是当我切换到HsqlDB时通过)
此外,如果我在测试开始时将延迟“Thread.sleep(1000)”延迟一秒,就在第一行之后,则此测试通过.
解决方法
在JPA中,日期需要时间提示.通常,您可以在设置JPA Query参数时设置TemporalType:
query.setParameter("from",from),TemporalType.TIMESTAMP);
使用Spring Data,您需要使用@Temporal
注释,因此您的查询将变为:
@Query("SELECT o FROM ConcreteOperation o WHERE o.beginTimestamp BETWEEN :from AND :to AND o.status = :status AND o.terminal.deviceId = :deviceId AND o.trainingMode = :trainingMode") Collection<ConcreteOperation> findOperations( @Param("from") @Temporal(TemporalType.TIMESTAMP) Date startDay,@Param("to") @Temporal(TemporalType.TIMESTAMP) Date endDay,@Param("trainingMode") boolean trainingMode );