FINERACT-2326: Enhanced loan retrieval API to avoid some of the N+1 queries when loading summaries

This commit is contained in:
Arnold Galovics
2025-08-24 22:03:56 +02:00
committed by Arnold Gálovics
parent 2a29b1ca0e
commit 9ef79f86a0
18 changed files with 262 additions and 46 deletions
@@ -281,7 +281,7 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
private void prepareDisbursementsOnLoanApplicationTerms(final LoanApplicationTerms loanApplicationTerms) {
if (loanApplicationTerms.getDisbursementDatas().isEmpty()) {
loanApplicationTerms.getDisbursementDatas()
.add(new DisbursementData(1L, loanApplicationTerms.getExpectedDisbursementDate(),
.add(new DisbursementData(1L, null, loanApplicationTerms.getExpectedDisbursementDate(),
loanApplicationTerms.getExpectedDisbursementDate(), loanApplicationTerms.getPrincipal().getAmount(), null, null,
null, null));
}
@@ -0,0 +1,28 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.loanaccount.repository;
import java.util.List;
import java.util.Map;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepaymentPeriodData;
public interface CustomizedLoanCapitalizedIncomeBalanceRepository {
Map<Long, List<LoanTransactionRepaymentPeriodData>> findRepaymentPeriodDataByLoanIds(List<Long> loanIds);
}
@@ -0,0 +1,58 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.loanaccount.repository;
import com.google.common.collect.Lists;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepaymentPeriodData;
import org.apache.fineract.util.StreamUtil;
@RequiredArgsConstructor
public class CustomizedLoanCapitalizedIncomeBalanceRepositoryImpl implements CustomizedLoanCapitalizedIncomeBalanceRepository {
private final EntityManager entityManager;
@Override
public Map<Long, List<LoanTransactionRepaymentPeriodData>> findRepaymentPeriodDataByLoanIds(List<Long> loanIds) {
List<List<Long>> partitions = Lists.partition(loanIds, DatabaseSpecificSQLGenerator.IN_CLAUSE_MAX_PARAMS);
return partitions.stream().map(this::doFindRepaymentPeriodDataByLoanIds).collect(StreamUtil.mergeMapsOfLists());
}
private Map<Long, List<LoanTransactionRepaymentPeriodData>> doFindRepaymentPeriodDataByLoanIds(List<Long> loanIds) {
// making the List serializable since sometimes it's just not
// Caused by: java.lang.IllegalArgumentException: You have attempted to set a value of type
// class java.util.ImmutableCollections$SubList for parameter loanIds with expected type of
// interface java.io.Serializable from query string ...
loanIds = new ArrayList<>(loanIds);
TypedQuery<LoanTransactionRepaymentPeriodData> query = entityManager.createQuery(
LoanCapitalizedIncomeBalanceRepository.FIND_BALANCE_REPAYMENT_SCHEDULE_DATA + " WHERE lcib.loan.id IN (:loanIds)",
LoanTransactionRepaymentPeriodData.class);
query.setParameter("loanIds", loanIds);
List<LoanTransactionRepaymentPeriodData> result = query.getResultList();
return result.stream().collect(Collectors.groupingBy(LoanTransactionRepaymentPeriodData::getLoanId));
}
}
@@ -26,8 +26,8 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
public interface LoanCapitalizedIncomeBalanceRepository
extends JpaRepository<LoanCapitalizedIncomeBalance, Long>, JpaSpecificationExecutor<LoanCapitalizedIncomeBalance> {
public interface LoanCapitalizedIncomeBalanceRepository extends JpaRepository<LoanCapitalizedIncomeBalance, Long>,
JpaSpecificationExecutor<LoanCapitalizedIncomeBalance>, CustomizedLoanCapitalizedIncomeBalanceRepository {
String FIND_BALANCE_REPAYMENT_SCHEDULE_DATA = "SELECT new org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepaymentPeriodData(lcib.loanTransaction.id, lcib.loan.id, lcib.loanTransaction.dateOf, lcib.loanTransaction.reversed, lcib.amount, lcib.unrecognizedAmount, lcib.loanTransaction.feeChargesPortion) FROM LoanCapitalizedIncomeBalance lcib ";