I am trying to retrieve name
, surname
, sum of balance
(by grouping by customer) and transaction
list by using a single database call by using Spring Data JPA @Query and Projection as shown below:
Here is the related entities; Customer
has many Accounts
, and Account
has many Transactions
(relations are defined properly using Hibernate).
public class Customer {
private Long id;
private String name;
private String surname;
}
public class Account {
private Long id;
private BigDecimal balance;
}
public class Transaction {
private Long id;
private Long accountId;
private LocalDateTime date;
}
I tried to map the Customer entity that has also Account and Transaction data to a DTO, but I could not map properly.
Then I tried to use the following query and then map the result to a projection, but the problem is that, it return records for each transaction.
@Query(value = "SELECT c.id AS id, c.name AS name, c.surname as surname, a.balance AS balance, " +
"t.id AS transactionId, t.description AS description, t.date AS date " +
"FROM Customer c " +
"LEFT JOIN Account a ON a.customer.id = c.id " +
"LEFT JOIN Transaction t ON a.id = t.account.id " +
"ORDER BY c.id")
List<CustomerDetailsResponse> findAllWithDetails();
Here is the returned result:
|id |name |surname |balance |t_id |date |
|---|-----------|-----------|-----------|-------|------------------------
|1 |Thorsten |Canto |100 |1 |2023-02-19 20:47:18.212|
|1 |Thorsten |Canto |200 |2 |2023-02-19 20:47:21.425|
|1 |Thorsten |Canto |300 |3 |2023-02-19 20:47:23.296|
|2 |Tailor |Bingham |300 |4 |2023-02-19 20:47:25.350|
|2 |Tailor |Bingham |500 |5 |2023-02-19 20:47:38.589|
|2 |Tailor |Bingham |600 |6 |2023-02-19 20:47:40.916|
|3 |Benson |Wilkowski |600 |7 |2023-02-19 20:47:42.675|
|3 |Benson |Wilkowski |800 |8 |2023-02-19 20:47:44.635|
|3 |Benson |Wilkowski |900 |9 |2023-02-19 20:47:47.436|
|3 |Benson |Wilkowski |1000 |10 |2023-02-19 20:47:51.328|
|4 |Pryce |Gorriessen | | | |
|5 |Melita |Griffoen | | | |
So, how can I achieve this by using Projection
or ModelMapper
or Java Stream
?
If you don't want all the transactions, but just the one associated to an account, I think u just have to substitute the left join with an inner join.
@Query(value = "SELECT c.id AS id, c.name AS name, c.surname as surname, a.balance AS balance, " +
"t.id AS transactionId, t.description AS description, t.date AS date " +
"FROM Customer c " +
"LEFT JOIN Account a ON a.customer.id = c.id " +
"JOIN Transaction t ON a.id = t.account.id " +
"ORDER BY c.id")
List<CustomerDetailsResponse> findAllWithDetails();