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

I have the following domain classes.

Credit class

@Data
@Entity
public class Loan {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    private String loanTitle;


    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "loan_id")
    private List<Allowance> allowances;
}

      

Permission class

@Data
@Entity
public class Allowance {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    private AllowanceType allowanceType;


    private Double allowanceAmount;

}

      

I also have a projection interface defined for the credit class as follows:

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

    String getLoanTitle();

    List<AllowanceProjection> getAllowances();

}

      

Now I want to include the total loan amount (which is calculated by iterating through the list of permissions) in the projection and send it to the UI. Is it possible to do this in Spring Data REST?

+3


source to share


2 answers


From here :

You can annotate public properties in Projection with using @Value

SpEL expressions to display synthetic properties. Even call methods on other Spring beans and pass a target to it for use in advanced computing .

So, you need to create a LoanRepo

bean method (for example) that will calculate the total amount of a 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 for example 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 the total amount:

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

      


Everything looks fine, but we have a "minor" problem. For each record, as a result, we get an additional query to the database, which calculates the total amount. So you are faced with N + 1 questions here .

You can find my research on this issue in SDR using Projections here .

+2


source


Putting domain objects on objects to solve the presentation of the representation (projection) is not the best solution.

A repository location would be useful for simple use cases, for complex problems where Java 8 will be present thanks default

to interface methods, 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;
    }
}

      

+1


source







All Articles