Spring Data REST - How to include calculated data in a projection?

只谈情不闲聊 提交于 2019-12-03 14:53:21

From here:

You can annotate exposed properties in Projection with @Value using SpEL expressions to expose synthetic properties. Even invoke methods on other Spring beans and hand over the target to it for use in advanced calculations.

So you have to create a LoanRepo bean method (for example) that calculate the total amount of the given loan:

@Query("select sum(a.allowanceAmount) as amount from Loan l join l.allowances a where l = ?1")
Double getTotalAmountByLoan(Loan loan);

and use like this Projection:

@Projection(name = "totalAmount", types = Loan.class)
public interface LoanTotalAmount {

    @Value("#{target}")
    Loan getLoan();

    @Value("#{@loanRepo.getTotalAmountByLoan(target)}")    
    Double getAmount();
}

Then you can get your loans with total amount:

GET http://localhost:8080/api/loans?projection=totalAmount

All looks fine but we have a 'small' issue here - for each record in the result we get an extra query to the DB that calculate total amount. So you faces here with 'N+1 queries issue`.

My investigation of this problem in SDR with Projections you can find here.

pdorgambide

Place on domain objects methods to solve a view representation (projection) is not the best solution.

Place on repository would be useful for simple use cases, for complex issues where Java 8 will be present thanks to default methods of interface you can use this simple trick.

@Projection(name = "studyLoanSingle", types = Loan.class)
public interface LoanProjection {

    String getLoanTitle();

    //If no need Allowances on json
    @JsonIgnore
    List<Allowance> getAllowances();

    public default Double getAmount() {
        Double result = new Double(0);
        for (Allowance a : getAllowances()) {
           result += a.getAllowanceAmount();            
        }
        return result;
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!