I have a batch procedure that collects approximately 275,000 records by fund. I've set the batch size to the maximum of 200 people. As a result, when the batch runs, 1,380 batches are processed.
All of the funds must be processed by name. Let's say I have a fund called "Fund A." "Fund A" may appear 10 times in the initial batch of 200 records, and "Fund A" is rolled up and inserted for those 10 entries.
The following 200 records are processed, and "Fund A" may appear five times in those 200 records. For those 5 records, "Fund A" is rolled up and inserted.
This procedure continues until all batches have been processed, at which point I end up with numerous records for "Fund A."
The following is taken from the batch apex documentation:
Each batch Apex job execution is treated as a separate transaction. A batch Apex task with 1,000 records that is run without the optional scope argument is treated as five transactions with 200 records each.
If Database is specified. You can keep state across these transactions if the class definition is stateful. When working with a database Only instance member variables that are stateful keep their values between transactions. Static member variables do not persist across transactions and are reset. Counting or summarising records while they're processed is aided by maintaining state. Assume you worked in a position where you handled opportunity records.
You might use execute to create a method that tallied the totals of the opportunity amounts as they were processed.
If I understand correctly, I can merge "Fund A" into a single record that spans all batches and then insert it?
I'm attempting to make use of a database.
I'm trying to use stateful, but I'm receiving the following error:
First error: Insert failed. First exception on row 1 with id a28e0000000uvHYAAY; first error: INVALID_FIELD_FOR_INSERT_UPDATE, cannot specify Id in an insert call: [Id]
Here is my batch code:
global class ProductionAggregateRollupBatch implements Database.Batchable<sObject>, Database.Stateful {
public string query = 'select DBR__c, FundName__r.Name, FundName__r.Class__c, PurchasesPY__c, PurchasesPYTD__c, PurchasesYTD__c, RedemptionsPY__c, RedemptionsPYTD__c, RedemptionsYTD__c, AUM__c from Production_Aggregate__c';
global Map<String, Funds_Purchased__c> rollupMap = new Map<String, Funds_Purchased__c>();
global database.querylocator start(Database.BatchableContext BC)
{
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext BC, Sobject[] scope)
{
Set<Id> dbrIds = new Set<Id>();
for (Production_Aggregate__c pa : (List<Production_Aggregate__c>)scope) {
dbrIds.add(pa.DBR__c);
}
Map<Id, List<Id>> dbrToContactMap = getDbrToContactMap(dbrIds);
for (Production_Aggregate__c pa : (List<Production_Aggregate__c>)scope) {
if(!dbrToContactMap.isEmpty() && dbrToContactMap.size() > 0) {
if(dbrToContactMap.containsKey(pa.DBR__c)) {
List<Id> contactIds = dbrToContactMap.get(pa.DBR__c);
for(Id contactId : contactIds) {
String index = '' + new String[] {
'' + pa.FundName__r.Name,
'' + contactId
};
Funds_Purchased__c fundPurchased = rollupMap.get(index);
if(fundPurchased == null) {
fundPurchased = new Funds_Purchased__c();
rollupMap.put(index, fundPurchased);
}
fundPurchased.Fund_Name__c = pa.FundName__r.Name;
fundPurchased.DBR__c = pa.DBR__c;
fundPurchased.Contact__c = contactId;