Skip to main content
added 1 character in body
Source Link
David Reed
  • 93.7k
  • 14
  • 90
  • 166

Is essentially that I'm going to hit limits and I know there are better ways to code this. If I'm correct, I'll have to store all current records into a map, then loop over that map X amount of times to check if it already exists?

This is a pretty good summary. Looking at your code, I think what you need to change is this.

for(Integer i = 0; i < 120; i++){
    currentDate = Date.today();
    firstDayOfCurrentMonth = currentDate.addMonths(i).toStartofMonth();
    lastDayOfCurrentMonth = currentDate.addMonths(i + 1).toStartofMonth().addDays(-1);

Instead of going straight to the generation of the Accounting Periods, let's generate a Set representing the key data points that define an already-existing Accounting Period. If that is the start date, for example, build a Set<Date>, and populate it with all the values you generate for firstDayOfCurrentMonth.

    List<AcctSeed__Accounting_Period__c> checkAccountingPeriodAlreadyExist = [SELECT Id, AcctSeed__Start_Date__c, AcctSeed__End_Date__c FROM AcctSeed__Accounting_Period__c where AcctSeed__Start_Date__c = :firstDayOfCurrentMonth];

This query is the key limits problem. It needs to be run exactly once, outside the for loop. If you generate a Set<Date> firstDaysOfMonths as mentioned above, you could change the query to

    List<AcctSeed__Accounting_Period__c> checkAccountingPeriodAlreadyExist = [SELECT Id, AcctSeed__Start_Date__c, AcctSeed__End_Date__c FROM AcctSeed__Accounting_Period__c where AcctSeed__Start_Date__c IN :firstDaysOfMonths];

Now we could, for fast O(1) access to determine if a given Accounting Period exists, convert this List into a Map<Date, AcctSeed__Accounting_Period__c> apMap, where the keys are the start dates, and then look at that Map while we iterate over the numbers 1 to 120 again to determine which records need to be created.

I actually think there's a faster way, though. Iterate over this list, and remove from the Set<DateSet<Date> all those records you already found:

for (AcctSeed__Accounting_Period__c ap : checkAccountingPeriodAlreadyExist) {
    firstDaysOfMonths.remove(ap.AcctSeed__Start_Date__c);
}

Then, lastly, you can iterate over the remaining start datesStart Dates that you generated in the first loop, build an Accounting Period for each one, and finally insert a single list of all the generated Accounting Periods.

If my thesis that the Start Date is unique was false, you can still follow something like this process; you'd just make changes to use a different field or combination of fields as your unique key, and the logic might be slightly more complex.

Is essentially that I'm going to hit limits and I know there are better ways to code this. If I'm correct, I'll have to store all current records into a map, then loop over that map X amount of times to check if it already exists?

This is a pretty good summary. Looking at your code, I think what you need to change is this.

for(Integer i = 0; i < 120; i++){
    currentDate = Date.today();
    firstDayOfCurrentMonth = currentDate.addMonths(i).toStartofMonth();
    lastDayOfCurrentMonth = currentDate.addMonths(i + 1).toStartofMonth().addDays(-1);

Instead of going straight to the generation of the Accounting Periods, let's generate a Set representing the key data points that define an already-existing Accounting Period. If that is the start date, for example, build a Set<Date>, and populate it with all the values you generate for firstDayOfCurrentMonth.

    List<AcctSeed__Accounting_Period__c> checkAccountingPeriodAlreadyExist = [SELECT Id, AcctSeed__Start_Date__c, AcctSeed__End_Date__c FROM AcctSeed__Accounting_Period__c where AcctSeed__Start_Date__c = :firstDayOfCurrentMonth];

This query is the key limits problem. It needs to be run exactly once, outside the for loop. If you generate a Set<Date> firstDaysOfMonths as mentioned above, you could change the query to

    List<AcctSeed__Accounting_Period__c> checkAccountingPeriodAlreadyExist = [SELECT Id, AcctSeed__Start_Date__c, AcctSeed__End_Date__c FROM AcctSeed__Accounting_Period__c where AcctSeed__Start_Date__c IN :firstDaysOfMonths];

Now we could, for fast O(1) access to determine if a given Accounting Period exists, convert this List into a Map<Date, AcctSeed__Accounting_Period__c> apMap, where the keys are the start dates, and then look at that Map while we iterate over the numbers 1 to 120 again to determine which records need to be created.

I actually think there's a faster way, though. Iterate over this list, and remove from the Set<Date all those records you already found:

for (AcctSeed__Accounting_Period__c ap : checkAccountingPeriodAlreadyExist) {
    firstDaysOfMonths.remove(ap.AcctSeed__Start_Date__c);
}

Then, lastly, you can iterate over the remaining start dates that you generated in the first loop, build an Accounting Period for each one, and finally insert a single list of all the generated Accounting Periods.

If my thesis that the Start Date is unique was false, you can still follow something like this process; you'd just make changes to use a different field or combination of fields as your unique key, and the logic might be slightly more complex.

Is essentially that I'm going to hit limits and I know there are better ways to code this. If I'm correct, I'll have to store all current records into a map, then loop over that map X amount of times to check if it already exists?

This is a pretty good summary. Looking at your code, I think what you need to change is this.

for(Integer i = 0; i < 120; i++){
    currentDate = Date.today();
    firstDayOfCurrentMonth = currentDate.addMonths(i).toStartofMonth();
    lastDayOfCurrentMonth = currentDate.addMonths(i + 1).toStartofMonth().addDays(-1);

Instead of going straight to the generation of the Accounting Periods, let's generate a Set representing the key data points that define an already-existing Accounting Period. If that is the start date, for example, build a Set<Date>, and populate it with all the values you generate for firstDayOfCurrentMonth.

    List<AcctSeed__Accounting_Period__c> checkAccountingPeriodAlreadyExist = [SELECT Id, AcctSeed__Start_Date__c, AcctSeed__End_Date__c FROM AcctSeed__Accounting_Period__c where AcctSeed__Start_Date__c = :firstDayOfCurrentMonth];

This query is the key limits problem. It needs to be run exactly once, outside the for loop. If you generate a Set<Date> firstDaysOfMonths as mentioned above, you could change the query to

    List<AcctSeed__Accounting_Period__c> checkAccountingPeriodAlreadyExist = [SELECT Id, AcctSeed__Start_Date__c, AcctSeed__End_Date__c FROM AcctSeed__Accounting_Period__c where AcctSeed__Start_Date__c IN :firstDaysOfMonths];

Now we could, for fast O(1) access to determine if a given Accounting Period exists, convert this List into a Map<Date, AcctSeed__Accounting_Period__c> apMap, where the keys are the start dates, and then look at that Map while we iterate over the numbers 1 to 120 again to determine which records need to be created.

I actually think there's a faster way, though. Iterate over this list, and remove from the Set<Date> all those records you already found:

for (AcctSeed__Accounting_Period__c ap : checkAccountingPeriodAlreadyExist) {
    firstDaysOfMonths.remove(ap.AcctSeed__Start_Date__c);
}

Then, lastly, you can iterate over the remaining Start Dates that you generated in the first loop, build an Accounting Period for each one, and finally insert a single list of all the generated Accounting Periods.

If my thesis that the Start Date is unique was false, you can still follow something like this process; you'd just make changes to use a different field or combination of fields as your unique key, and the logic might be slightly more complex.

Source Link
David Reed
  • 93.7k
  • 14
  • 90
  • 166

Is essentially that I'm going to hit limits and I know there are better ways to code this. If I'm correct, I'll have to store all current records into a map, then loop over that map X amount of times to check if it already exists?

This is a pretty good summary. Looking at your code, I think what you need to change is this.

for(Integer i = 0; i < 120; i++){
    currentDate = Date.today();
    firstDayOfCurrentMonth = currentDate.addMonths(i).toStartofMonth();
    lastDayOfCurrentMonth = currentDate.addMonths(i + 1).toStartofMonth().addDays(-1);

Instead of going straight to the generation of the Accounting Periods, let's generate a Set representing the key data points that define an already-existing Accounting Period. If that is the start date, for example, build a Set<Date>, and populate it with all the values you generate for firstDayOfCurrentMonth.

    List<AcctSeed__Accounting_Period__c> checkAccountingPeriodAlreadyExist = [SELECT Id, AcctSeed__Start_Date__c, AcctSeed__End_Date__c FROM AcctSeed__Accounting_Period__c where AcctSeed__Start_Date__c = :firstDayOfCurrentMonth];

This query is the key limits problem. It needs to be run exactly once, outside the for loop. If you generate a Set<Date> firstDaysOfMonths as mentioned above, you could change the query to

    List<AcctSeed__Accounting_Period__c> checkAccountingPeriodAlreadyExist = [SELECT Id, AcctSeed__Start_Date__c, AcctSeed__End_Date__c FROM AcctSeed__Accounting_Period__c where AcctSeed__Start_Date__c IN :firstDaysOfMonths];

Now we could, for fast O(1) access to determine if a given Accounting Period exists, convert this List into a Map<Date, AcctSeed__Accounting_Period__c> apMap, where the keys are the start dates, and then look at that Map while we iterate over the numbers 1 to 120 again to determine which records need to be created.

I actually think there's a faster way, though. Iterate over this list, and remove from the Set<Date all those records you already found:

for (AcctSeed__Accounting_Period__c ap : checkAccountingPeriodAlreadyExist) {
    firstDaysOfMonths.remove(ap.AcctSeed__Start_Date__c);
}

Then, lastly, you can iterate over the remaining start dates that you generated in the first loop, build an Accounting Period for each one, and finally insert a single list of all the generated Accounting Periods.

If my thesis that the Start Date is unique was false, you can still follow something like this process; you'd just make changes to use a different field or combination of fields as your unique key, and the logic might be slightly more complex.