0

I have the custom object Project, which has a child Payers. One project can have more than one Payer. Payer has a field called Billing Percentage. Payer is a child of Account and Project has a lookup to Account, but right now all Project instances have no Account associated with them, while all Payers are associated with an Account.

I am trying to do a batch job where I do the following:

  1. For each Project, find the Payer with the highest Billing Percentage;
  2. Update the Account relationship of each project to have the Account of the Payer with the highest percentage

This is the code I have so far, and it does nothing when I execute the batch job (as far as I can tell).

global class ObjectFieldSwap implements Database.Batchable<sObject> {
    global String query;
    global Map<sObject,Double> percentages;
    global List<Double> sortedPercentages;
    global Double maxPercent = 0.0;
    global Double currentPercent = 0.0;
    global sObject maxAccount;

    global Database.QueryLocator start(Database.BatchableContext bc){
        query = 'SELECT Name, (SELECT Pourcentage_de_facturation__c FROM Payants__r) FROM pse__Proj__c';
        return Database.getQueryLocator(query);
    }

    global void execute(Database.BatchableContext bc, List<pse__Proj__c> scope){
        for(pse__Proj__c s : scope){
            for(Payant__c p : s.Payants__r){
                percentages.put(p.getSObject('Account__r'), Double.valueOf(p.get('Pourcentage_de_facturation__c')));
            }
            for(sObject a : percentages.keySet()){
                currentPercent = percentages.get(a);
                if(currentPercent>maxPercent){
                    maxPercent = currentPercent;
                    maxAccount = a;
                }
            }

            s.put('pse__Account__c', maxAccount);
        }
    }

    global void finish(Database.BatchableContext bc){

    }
}

I am very new to Apex and Salesforce so I think there might definitely be some problems with the types of objects or relationships that I use, any help in that area would be greatly appreciated.

**For clarity: pse__Proj__c = Project

Payant = Payer

Pourcentage_de_facturation_c = Billing Percentage

1
  • 1
    Hi @Renaud, no need to mention that you are new, or thanks in your posts, try to keep things simple and clear and take some time to take the tour and review How to Ask . Welcome to the forum!
    – glls
    May 9, 2017 at 17:56

1 Answer 1

4

If you want to persist your changes in the database, you have to perform a DML Operation (in this case update):

for (MyObject__c record : scope)
{
    // manipulate data
}
update scope;

I would also recommend a few changes:

  • Change all global access modifiers to public.
  • In general if you want to map by a record, use its Id as the key, not the object itself. Hashing complex objects is a bit tricky and can lead to unpredictable results if you're not careful.
  • You don't need a map at all, here. You can add ORDER BY and LIMIT clauses to your sub-query to great effect here:

    (SELECT Id FROM Payants__r ORDER BY Pourcentage_de_facturation__c DESC LIMIT 1)
    

    Then in your execute method:

    for (MyObject__c record : scope)
    {
        if (!record.Payants__r.isEmpty())
        {
            record.Account__c = record.Payants__r[0].Id;
        }
    }
    update scope;
    
1
  • 1
    Good answer. Just some notes for new Salesforce devs reading this. There are a few reasons that the global access modifier should be used only where truly necessary, a big one being that you can't remove/modify global classes/method signatures once they are in your org. Also, bulkifying the DML operation is important because Salesforce has DML limits that you can hit quickly if you aren't careful, and bulkifying can drastically reduce the number of operations you are performing.
    – zgc7009
    May 9, 2017 at 19:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .