As @eyescream and @Sdry stated you should do some preprocessing to build up a Set/List of Ids to supply to your SOQL query. You can create maps that can then be used after bulk queries are done. These sort of bulk patterns of building up a collection of Ids for a SOQL query is extremely common in Apex.
This shows using the LoanInfo and assumes that the EquipmentID will be unique in the batch.
Map<Id, LoanInfo> equipmentToLoanInfo = new Map<Id, LoanInfo>();
Set<Id> loanedToIds = new Set<Id>();
for(LoanInfo LI : LoanInfos)
{
// Map Equipment ID to Loan Info.
// Will use keySet() in query later
equipmentToLoanInfo.put(LI.EquipmentID, LI);
// store off all of the Ids for later queries
loanedToIds.add(LI.LoanedTo);
}
Map<Id, User> dbUsers = new Map<Id, User>([
Select <a bunch of fields>
From User
Where Id In :loanedToIds
]);
// create Same type of maps for other LoanedTo types...
for(Equipment_Loan__c objELOld : [
select <a bunch of fields>
from Equipment_Loan__c
where Equipment__c In :LI.equipmentToLoanInfo.keySet() and Actual_Return_Date__c=null
])
{
LoanInfo equipLoanInfo = equipmentToLoanInfo.get(objELOld.Equipment__c);
if (equipLoanInfo.LoanType == 'User') {
dbUser = dbUsers.get(equipLoanInfo.LoanedTo);
// set the fields...
} else if (equipLoanInfo.LoanType == 'Contact') {
// same as user, but with contact
} // continue with other types...
}
If all that you are doing is using the SF Data Loader on the Equipment_Loan__c and all that you need to do is hookup values on a trigger (e.g., before insert, etc.) then you can change the above to use a Map of Equipment_Loan__c records instead of LoanInfo, e.g.,:
Map<Id, Equipment_Loan__c> equipmentToLoanInfo = Trigger.NewMap;
Set<Id> loanedToIds = new Set<Id>();
for(Id eId : equipmentToLoanInfo.keySet())
{
Equipment_Loan__c equipLoan = equipmentToLoanInfo.get(eId);
// store off all of the Ids for later queries
loanedToIds.add(equipLoan.LoanedTo);
}
// Basically the same code as when using Map<Id, LoanInfo>,
// but change to use Equipment_Loan__c
The other type of situation that you can run into is where you may need to map a one to many. For example, if your LoanInfos within the same batch could share an EquipmentID, you might want to use processing such as the following.
Map<Id, List<LoanInfo>> equipmentToLoanInfos = new Map<Id, List<LoanInfo>>();
for (LoanInfo LI : LoanInfos) {
if (equipmentToLoanInfos.get(LI.EquipmentID) == null) {
equipmentToLoanInfos.put(LI.EquipmentID, new List<LoanInfo>());
}
equipmentToLoanInfos.get(LI.EquipmentID).add(LI);
}
This common case that leads to this idea is having a loop over a list of records with a query inside the loop. Works fine initially when there are only a few records but breaks when there are more records. The number of records is indeterminate. And the coding pattern to handle that is usually to move the nested query out of the loop and hold its results in a map that is referenced inside the loop.
Your case requires the 35 queries - there is no other (simple) way to do the work. Here, the number of records is determinate. So personally, I would add a comment explaining why you have made this design choice, and if over time more queries are added resulting in that or other limits being exceeded, refactor then.
Be wary of words like "best" in software that imply that there is one always ideal solution. This post The Law of Demeter Is Not A Dot Counting Exercise about a "law" includes the Martin Fowler comment:
I'd prefer it to be called the Occasionally Useful Suggestion of Demeter
Best Answer
This will be the Alias Notation for objects. E.g.
In your case
LIMIT43
is actually an alias forUser
. So you will find this works as well: