I am working on a mini banking app. I want to query the database in which all the transactions made so far are stored with three query parameters which are, user account,startDate and endDate. the database has a column for transactionDate which is of type Date. I want a situation in which if the user provide something like 2022-10-21 as start date and 2022-08-02 as the end date, and then provide his account number. The query should return a list of all the transactions made by that particular user using the user’s account number by querying the transactionDate column to get the date for each transactions. That’s a transaction between 2022-10-21 to 2022-08-02 for that user.
This is what I have tried so far but still getting this error
Caused by: org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.util.List com.elijah.onlinebankingapp.repository.transaction.TransactionTypeRepository.findByBankAccountAndTransactionDate(com.elijah.onlinebankingapp.model.account.BankAccount,java.util.Date,java.util.Date)! Reason: Validation failed for query for method public abstract java.util.List com.elijah.onlinebankingapp.repository.transaction.TransactionTypeRepository.findByBankAccountAndTransactionDate(com.elijah.onlinebankingapp.model.account.BankAccount,java.util.Date,java.util.Date)!; nested exception is java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List com.elijah.onlinebankingapp.repository.transaction.TransactionTypeRepository.findByBankAccountAndTransactionDate(com.elijah.onlinebankingapp.model.account.BankAccount,java.util.Date,java.util.Date)!
This is my TransactionType model class
@Entity
@NoArgsConstructor
@Data
public class TransactionType {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Date transactionDate;
private double amount;
private double currentBalance;
private String transactionType;
private String description;
private String depositorOrWithDrawalName;
@ManyToOne
@JoinColumn(name = "account_id")
private BankAccount bankAccount;
}
The BankAccount class
@Entity
@Data
@NoArgsConstructor
@Slf4j
public class BankAccount {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String accountType;
private String accountStatus;
private String accountNumber;
private double currentBalance;
private LocalDate createdDate;
@OneToOne
@JoinColumn(name = "customer_id")
private Customer customer;
}
my BankAccountStatement class
@Data
@NoArgsConstructor
public class BankAccountStatement {
private double id;
private String transactionDate;
private String transactionType;
private String description;
private double amount;
private double currentBalance;
private String depositorOrWithDrawalName;
}
BankAccountStatementDto
@Data
@NoArgsConstructor
public class BankAccountStatementDto {
private Date startDate;
private Date endDate;
}
my repository in which I did the query
@Repository
public interface TransactionTypeRepository extends JpaRepository<TransactionType,Long> {
@Query("select t from TransactionType t where t.bankAccount =:bankAccount, t.transactionDate <=:startDate AND t.transactionDate >=:endDate")
List<TransactionType> findByBankAccountAndTransactionDate(BankAccount bankAccount, @Param("startDate") Date startDate,@Param("endDate") Date endDate);
}
my service class
@Service
public class TransactionTypeService {
@Autowired
private TransactionTypeRepository transactionTypeRepository;
@Autowired
private BankAccountService bankAccountService;
public List<BankAccountStatement> getUserAccountStatement(BankAccountStatementDto bankAccountStatementDto, String accountNumber) throws DataNotFoundException {
BankAccount bankAccount = bankAccountService.getAccountByAccountNumber(accountNumber);
List<TransactionType> transactionTypeList = transactionTypeRepository.findByBankAccountAndTransactionDate(bankAccount,bankAccountStatementDto.getStartDate(),bankAccountStatementDto.getEndDate());
//the TransactionType has so many data and I don't need all the data in it
//I only want to retrieve the important information and store on this BankAccountStatement
List<BankAccountStatement> bankAccountStatementList = new ArrayList<>();
BankAccountStatement bankAccountStatement = new BankAccountStatement();
for (TransactionType transactionType: transactionTypeList){
bankAccountStatement.setId(transactionType.getId());
bankAccountStatement.setTransactionType(transactionType.getTransactionType());
bankAccountStatement.setTransactionDate(transactionType.getTransactionDate().toString());
bankAccountStatement.setDescription(transactionType.getDescription());
bankAccountStatement.setDepositorOrWithDrawalName(transactionType.getDepositorOrWithDrawalName());
bankAccountStatement.setCurrentBalance(transactionType.getCurrentBalance());
bankAccountStatement.setAmount(transactionType.getAmount());
bankAccountStatementList.add(bankAccountStatement);
}
return bankAccountStatementList;
}
}
my controller
@RestController
public class TransactionController {
@Autowired
private TransactionTypeService transactionTypeService;
@GetMapping("/account/statement/from/enteredDate")
public ResponseEntity<List<BankAccountStatement>> getCustomerAccountStatement(@RequestBody BankAccountStatementDto bankAccountStatementDto,@RequestParam("accountNumber")String accountNumber) throws DataNotFoundException {
return new ResponseEntity<>(transactionTypeService.getUserAccountStatement(bankAccountStatementDto,accountNumber),HttpStatus.OK);
}
}
2
Answers
I have solved the issue, the problem was from my query, I was using a comma after the bankAccount instead of AND. This is the final solution in case anyone has such a problem
The problem is with your transactionDate field. You have to let the hibernate know whether it holds only date, only time, or both. Assuming you are using java.util.Date, it contains both date and time upto milliseconds. @Temporal annotation in sprint boot will let know the hibernate about what data it holds.
In your case, you should add @Temporal(TemporalType.TIMESTAMP) for transactionDate field (assuming you are using java.util.Date).
You have other temporal types as well,
TemporalType.DATE – only date, TemporalType.TIME – only time