0

I'm working with AbhinavGupta's LREngine trigger & class to get around summary roll-up field limits, and having some trouble modifying his trigger (I'm learning Apex, but slowly, as coding is entirely new to me).

Key question: I want to add filters to the trigger so that it only recalculates the master rollup fields if the detail fields were actually changed.

I saw this post and used the answer there for some help, but I think it may be flawed (or at least doesn't apply for isChanged scenarios). I tried to leverage what I know about oldMap and newMap values from SFDC99, and looks like the error lays with making a List in line 19 (in sfdc99 he uses a Set, so I'm not surprised I have an error here). I get the error "Error: Compile Error: Initial term of field expression must be a concrete SObject: List at line 19 column 45"

Larger frame of reference: Total_Ad_Fees__c is a field that is frequently updated on our location records, so I hadn't bothered with this filter when I originally created the trigger, but Beacons_Here__c is updated much less frequently, and I don't think it should be recalculated with every update. I know one of the great things about Gupta's LREngine is that you can combine rollups into one trigger like this rather than creating separate triggers, so I did -- and I'd like to add more to this as well. (We have a few lookup relationship fields between Location__c and Accounts and I'd love to have a rollup COUNT field of those on Accounts -- though I believe that would need to be a separate trigger regardless because I'm not sure I can create multiple contexts within this one trigger. If you have any advice there, also greatly appreciated, though I need to tackle this first!)

So - should I even be trying to filter these? My gut is yes. But if so, how do I resolve the error, and can I do it in a way that allows me to still have multiple fields rolled up in the same trigger?

Here is the code that is giving me the error:

trigger merchantAdFeeRollUp on Location__c (after update, 
                                    after delete, after undelete) {
  // modified objects whose parent records should be updated
 Location__c[] locs = null;   

 if (Trigger.isDelete) {
     locs = Trigger.old;
 } else {
    /*
        Handle any filtering required, specially on Trigger.isUpdate event. If the rolled up fields
        are not changed, then please make sure you skip the rollup operation.
        We are not adding that for sake of similicity of this illustration.
    */ 
    locs = Trigger.new;
 }

List<Location__c> toUpdate  = new List<Location__c>();
 for(Location__c l : locs){
  String oldAdFees = Trigger.oldMap.get(locs.Id).Total_Ad_Fees__c;
  String newAdFees = locs.Total_Ad_Fees__c;
  String oldBeaconCount = Trigger.oldMap.get(locs.Id).Beacons_Here__c;
  String newBeaconCount = locs.Beacons_Here__c;

  if(oldAdFees != newAdFees || oldBeaconCount != newBeaconCount){
    toUpdate.add(l);
  }    
 }    

 /*
  First step is to create a context for LREngine, by specifying parent and child objects and
  lookup relationship field name
 */
 LREngine.Context ctx = new LREngine.Context(Merchant__c.SobjectType, // parent object
                                        Location__c.SobjectType,  // child object
                                        Schema.SObjectType.Location__c.fields.Merchant__c // relationship field name
                                        );     
 /*
  Next, one can add multiple rollup fields on the above relationship. 
  Here specify 
   1. The field to aggregate in child object
   2. The field to which aggregated value will be saved in master/parent object
   3. The aggregate operation to be done i.e. SUM, AVG, COUNT, MIN/MAX
 */
 ctx.add(
        new LREngine.RollupSummaryField(
                                        Schema.SObjectType.Merchant__c.fields.Total_Merchant_Ad_Fees__c,
                                        Schema.SObjectType.Location__c.fields.Total_Ad_Fees__c,
                                        LREngine.RollupOperation.Sum 
                                     )); 

 ctx.add(
        new LREngine.RollupSummaryField(
                                        Schema.SObjectType.Merchant__c.fields.Total_Beacons__c,
                                        Schema.SObjectType.Location__c.fields.Beacons_Here__c,
                                        LREngine.RollupOperation.Sum 
                                     )); 


 /* 
  Calling rollup method returns in memory master objects with aggregated values in them. 
  Please note these master records are not persisted back, so that client gets a chance 
  to post process them after rollup
  */ 
 Sobject[] masters = LREngine.rollUp(ctx, toUpdate);    

 // Persiste the changes in master
 update masters;

}

For reference, here is the unfiltered code I started with, which has been working fine:

trigger merchantAdFeeRollUp on Location__c (after update, 
                                    after delete, after undelete) {
  // modified objects whose parent records should be updated
 Location__c[] objects = null;   

 if (Trigger.isDelete) {
     objects = Trigger.old;
 } else {
    /*
        Handle any filtering required, specially on Trigger.isUpdate event. If the rolled up fields
        are not changed, then please make sure you skip the rollup operation.
        We are not adding that for sake of similicity of this illustration.
    */ 
    objects = Trigger.new;
 }

 /*
  First step is to create a context for LREngine, by specifying parent and child objects and
  lookup relationship field name
 */
 LREngine.Context ctx = new LREngine.Context(Merchant__c.SobjectType, // parent object
                                        Location__c.SobjectType,  // child object
                                        Schema.SObjectType.Location__c.fields.Merchant__c // relationship field name
                                        );     
 /*
  Next, one can add multiple rollup fields on the above relationship. 
  Here specify 
   1. The field to aggregate in child object
   2. The field to which aggregated value will be saved in master/parent object
   3. The aggregate operation to be done i.e. SUM, AVG, COUNT, MIN/MAX
 */
 ctx.add(
        new LREngine.RollupSummaryField(
                                        Schema.SObjectType.Merchant__c.fields.Total_Merchant_Ad_Fees__c,
                                        Schema.SObjectType.Location__c.fields.Total_Ad_Fees__c,
                                        LREngine.RollupOperation.Sum 
                                     )); 

 ctx.add(
        new LREngine.RollupSummaryField(
                                        Schema.SObjectType.Merchant__c.fields.Total_Beacons__c,
                                        Schema.SObjectType.Location__c.fields.Beacons_Here__c,
                                        LREngine.RollupOperation.Sum 
                                     )); 


 /* 
  Calling rollup method returns in memory master objects with aggregated values in them. 
  Please note these master records are not persisted back, so that client gets a chance 
  to post process them after rollup
  */ 
 Sobject[] masters = LREngine.rollUp(ctx, objects);    

 // Persiste the changes in master
 update masters;

}

Help?

6
  • you might want to look at Andrew Fawcett's Declarative Lookup Rollup Summary package (free) that incorporates the LREngine and presents a point-and-click solution for configuring RSF use cases not provided OOB by SFDC – cropredy Jun 4 '15 at 16:10
  • @crop1645 I've been looking at it and am heavily considering it. Do you have any experience with it? I'm a little worried that I wouldn't be able to debug any errors that come up, but I'm not sure that would put me in any worse place than I already am! – mlpSFadmin Jun 4 '15 at 20:53
  • yes - I have used this and it works fine. There is great support from the developers of the package on their GitHub page - you can verify for yourself by looking at the Issues link. DLRS is often recommended by others here on SFSE – cropredy Jun 5 '15 at 0:35
  • @crop1645 Sorry for the radio silence on this, but I've gone ahead, bit the bullet, and installed DLRS. Loving it so far, but I'm still configuring. Thanks for the confidence boost that it would be worth my while!!! – mlpSFadmin Jun 11 '15 at 20:07
  • good luck - @AndrewFawcett is a very smart guy and he has a great book 'Force.com Enterprise Architecture' which may forever change the way you structure your apex infrastructure in an org (Disclaimer - I don't work for FinancialForce and have no vested interest in Andy's company) – cropredy Jun 11 '15 at 22:05
0

I haven't gone through your entire code yet, however the compile error you are getting is due to you trying to retrieve the field value on a list of objects, rather than accessing the object itself.

The Fix: you need to replace locs with l in the code in the for loop

for(Location__c l : locs){
    String oldAdFees = Trigger.oldMap.get(locs.Id).Total_Ad_Fees__c; // .get(l.Id).
    String newAdFees = locs.Total_Ad_Fees__c; // l.Total....
    String oldBeaconCount = Trigger.oldMap.get(locs.Id).Beacons_Here__c; // .get(l.Id).
    String newBeaconCount = locs.Beacons_Here__c; // l.Beac.....

    if(oldAdFees != newAdFees || oldBeaconCount != newBeaconCount){
        toUpdate.add(l);
    }    
}

Explanation: try this and look at your debug files

for (Location__c l : locs) {
    system.debug(l);    //this will have the one record and it's values
    system.debug(locs); //this will be the list of records still
}

Another way at looking at this same piece of code (because I know people get tripped on this all the time) if we break it out into a traditional iterative for loop:

for (Integer i = 0; i < locs.size(); i++) {
    Location__c l = locs[1];

    //... your code here....
}
2
  • Thanks, ben for this! I figured it was something to do with iterating, but I never feel particularly comfortable with those! Rookie mistake I suppose, but somehow I find it incredibly difficult to look at my own work and recognize these things! – mlpSFadmin Jun 11 '15 at 20:10
  • All good, reading your own code can be harder than reading others a lot of the time :-) – Ben Naylor Jun 11 '15 at 21:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.