javaspring-bootspring-data-jpajava-streammodelmapper

Cannot map joined table data using Projection, etc. in Spring Data JPA


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?


Solution

  • 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();