How to make native query for nested projection in Spring Data JPA

379 Views Asked by At

I need to write a native query for my projection with nested interfaces.

My TransactionView interface:

public interface TransactionView {
    
    Long getId();
    
    TransactionType getType();
    
    LocalDate getDate();
    
    AccountProjection getAcc1();
    
    AccountProjection getAcc2();
    
    interface AccountProjection {
        String getName();
        CurrencyName getCurrencyCode();
        BigDecimal getBalance();
    }
    
    BigDecimal getAmount();
    
    PartnerView getPartner();
    
    interface PartnerView {
        String getName();
    }
    
    String getComment();
    
    CategoryView getCategory();
    
    interface CategoryView {
        String getName();
    }
}

JpaRepository:

public interface TransactionsRepository extends JpaRepository<Transaction, Long> {
  List<TransactionView> findByAcc1PersonIdOrderByDateDesc(int personId); 
}

This approach works good and I get JSON like this:

[{
 "id":34,
 "type":"TRANSFER",
 "comment":"test comment",
 "date":"2022-12-23",
 "amount":200.00,
 "acc2":
        {
         "name":"cash",
         "currencyCode":"USD",
         "balance":200.00
        },
 "acc1":
        {
         "name":"test acc",
         "currencyCode":"USD",
         "balance":700.00
         },
 "partner":null,
 "category":null
 },
 {
 "id":20,
 "type":"EXPENCE",
 "comment":"",
 "date":"2022-12-13",
 "amount":33.07,
 "acc2":null,
 "acc1":
       {
        "name":"cash",
        "currencyCode":"BYN",
        "balance":322.33
       },
 "partner":
       {
        "name":"bmw"
       },
 "category":
       {
        "name":"auto"
       }
}]

But Hibernate generates a very complex query with a lot of extra columns fetching.

My native query returns null nested objects:

@Query(value = "SELECT t.id AS id, " +
        "t.transaction_type AS type, " +
        "t.transaction_date AS date, " +
        "t.amount AS amount, " +
        "t.comment AS comment, " +
        "a1.balance AS acc1Balance, " +
        "a1.currency_code AS acc1CurrencyCode, " +
        "a1.name AS acc1Name, " +
        "a2.balance AS acc2Balance, " +
        "a2.currency_code AS acc2CurrencyCode, " +
        "a2.name AS acc2Name, " +
        "par.name AS partnerName, " +
        "cat.name AS categoryName, " +
        "cat.category_type AS categoryType " +
        "FROM transaction t " +
        "LEFT OUTER JOIN account a1 ON t.acc1_id=a1.id " +
        "LEFT OUTER JOIN person per ON a1.person_id=per.id " +
        "LEFT OUTER JOIN account a2 ON t.acc2_id=a2.id " +
        "LEFT OUTER JOIN partner par ON t.partner_id=par.id " +
        "LEFT OUTER JOIN category cat ON t.category_id=cat.id " +
        "WHERE per.id=?1 ORDER BY t.transaction_date DESC", nativeQuery = true)
    List<TransactionView> findByAcc1PersonIdOrderByDateDescTest(int personId);
[{
 "id":34,
 "type":"TRANSFER",
 "comment":"test comment",
 "date":"2022-12-23",
 "amount":200.00,
 "acc2":null,
 "acc1":null,
 "partner":null,
 "category":null
 },
 {
 "id":20,
 "type":"EXPENCE",
 "comment":"",
 "date":"2022-12-13",
 "amount":33.07,
 "acc2":null,
 "acc1":null,
 "partner":null,
 "category":null
}]

Also I tried approach from Peter Gyschuk, but it doesn't work.

How can I solve it using native query?

0

There are 0 best solutions below