1

I am trying to set a boolean to true upon insert based on first this logic:

if((pr.recordtypeid == '012g0000000D63fAAC' || pr.recordtypeid == '012g0000000D63iAAC' || pr.recordtypeid == '012g0000000D63gAAC' || pr.recordtypeid == '012g0000000D63kAAC' ||
   pr.recordtypeid == '012g0000000D63jAAC' || pr.recordtypeid == '012g0000000D63TAAS' || pr.recordtypeid == '012g0000000D63RAAS' || pr.recordtypeid == '012g0000000D63UAAS') 
   &&  pr.route_code__c == 'H - HCFA Print Image (HCFA to NSF)' && pr.Transaction_Format__c== 'S - NSF 3.01' )

and that a record of the same account that is of Emdeon One - Client, '012g0000000D63W' that has print image__c = true.

I am not sure how compose this logic but here is what I have and am getting

AfterInsert caused by: System.FinalException: Record is read-only: Trigger.eOneProdConfigUpdatePrintImage: line 58, column 1

code

trigger eOneProdConfigUpdatePrintImage on Product_Configuration__c (after insert) {

/*RecTypes
"012g0000000D63eAAC","275"
"012g0000000D63fAAC","837"
"012g0000000D63gAAC","837D"
"012g0000000D63hAAC","837DW"
"012g0000000D63iAAC","837I"
"012g0000000D63jAAC","837IW"
"012g0000000D63kAAC","837W"
"012g0000000D63RAAS","CSI"
"012g0000000D63SAAS","EDGE"
"012g0000000D63TAAS","ELG"
"012g0000000D63VAAS","Emdeon One - Channel Partner"
"012g0000000D63WAAS","Emdeon One - Client"
"012g0000000D63XAAS","Emdeon One - Data"
"012g0000000D63YAAS","Emdeon One - Fiscal Intermediary"
"012g0000000D63ZAAS","Emdeon One - Payer"
"012g0000000D63UAAS","ERA"
"012g0000000D63aAAC","Payment"
"012g0000000D63bAAC","Portal Services"
"012g0000000D63cAAC","RFI"
"012g0000000D63dAAC","RFR"*/

set<id> prid = new set<id>();
set<id> acctids = new set<id>();
Map<String, Integer> configmap = new Map<String, Integer>();
List<product_configuration__c>pr2upt = new list<product_configuration__c>();

Integer cnt;
Id acctid;

List<Product_Configuration__c> prodlist = [Select Id, Route_Code__c, ES_Format__c, Account__c from product_configuration__c where recordtypeid = '012g0000000D63W'];

For(product_configuration__c pr: trigger.new)  {

if((pr.recordtypeid == '012g0000000D63fAAC' || pr.recordtypeid == '012g0000000D63iAAC' || pr.recordtypeid == '012g0000000D63gAAC' || pr.recordtypeid == '012g0000000D63kAAC' ||
   pr.recordtypeid == '012g0000000D63jAAC' || pr.recordtypeid == '012g0000000D63TAAS' || pr.recordtypeid == '012g0000000D63RAAS' || pr.recordtypeid == '012g0000000D63UAAS') 
   &&  pr.route_code__c == 'H - HCFA Print Image (HCFA to NSF)' && pr.Transaction_Format__c== 'S - NSF 3.01' ) {

prid.add(pr.Id); 
acctids.add(pr.Account__c);
pr2upt.add(pr);

AggregateResult[] groupedResults = [Select Account__c, count(Name) From Product_Configuration__c where Account__c in : acctids Group by Account__c];  

For(AggregateResult ar : groupedresults) {

cnt = (Integer) ar.get('expr0');
acctid = (Id) ar.get('Account__c');
configmap.put(acctid, cnt);  

For(Product_Configuration__c emd1 : prodlist) {


if(emd1.Print_Image__c = true && (configmap.containskey(acctid)) )   {

pr.Print_Image__c = true;



                         }
                       }


                   } 
                 }

              }
              update pr2upt;

            } 
2
  • Why your are not using before inser trigger ? May 23, 2015 at 1:39
  • Thanks Vamsi, I totally missed that. It works perfectly.
    – Zane
    May 23, 2015 at 3:15

1 Answer 1

0

I was too tired to post last night, but in an after trigger, trigger.new is read only. The line pr.Print_Image__c = true; was trying to change a value in trigger.new, thus the cause of your error message.

If you'd have ended this loop:

For(product_configuration__c pr: trigger.new)  {` 

after the line with pr2upt.add(pr);

Then started a new For loop based on the list pr2upt after the line:

configmap.put(acctid, cnt);

you could have kept things as an AfterUpdate trigger.

Regardless of whether this is executed as a BeforeInsert or an AfterInsert Trigger, there are things that to me, appear to need to be revised. One very important change that needs to be made is to prevent your trigger from automatically running queries that may not be necessary every time the trigger runs.

The following loop

For(AggregateResult ar : groupedresults) { 

needs to be closed after configmap.put(acctid, cnt);.

Once you do that, if done as an After Trigger, the following line could then become:

For(Product_Configuration__c emd1 : pr2upt) {

There's no need to loop through your entire product list when you've already filtered out the Id's of the products that need updated! This would easily be facilitated had initialized your query at the start of your trigger as a map like this:

map<Id,Product_Configuration__c>plmap = new map([Select Id, Route_Code__c, ES_Format__c, Account__c from product_configuration__c where recordtypeid = '012g0000000D63W']);

You could then do something like this:

   if(plmap.get(emd1.Id).Print_Image__c = true && (configmap.containskey(emd1.Account__c)) )   {

      emd1.Print_Image__c = true;          

   }

As an AfterInsert, your trigger would like what's below. A BeforeInsert should look similar in terms of breaking it into separate loops with the AggregateResult in the middle (look at a debug log and you'll see what I mean) but you'd repeat the last loop using variables that still operate on trigger.new.

Here's the body of the code:

trigger eOneProdConfigUpdatePrintImage on Product_Configuration__c (after insert) {

set<id> prid = new set<id>();
set<id> acctids = new set<id>();
Map<String, Integer> configmap = new Map<String, Integer>();
List<product_configuration__c>pr2upt = new list<product_configuration__c>();
Id acctid;
AggregateResult[] groupedResults = new AggregateResult[];

map<Id,Product_Configuration__c>plmap = new map<Id,Product_Configuration__c>();

For(product_configuration__c pr: trigger.new)  {

   if((pr.recordtypeid == '012g0000000D63fAAC' || pr.recordtypeid == '012g0000000D63iAAC' || pr.recordtypeid == '012g0000000D63gAAC' || pr.recordtypeid == '012g0000000D63kAAC' ||
   pr.recordtypeid == '012g0000000D63jAAC' || pr.recordtypeid == '012g0000000D63TAAS' || pr.recordtypeid == '012g0000000D63RAAS' || pr.recordtypeid == '012g0000000D63UAAS') 
   &&  pr.route_code__c == 'H - HCFA Print Image (HCFA to NSF)' && pr.Transaction_Format__c== 'S - NSF 3.01' ) {

      prid.add(pr.Id); 
      acctids.add(pr.Account__c);
      pr2upt.add(pr);
   } // end if(pr.recordtypeid ==
} // end For(product_configuration__c pr: trigger.new)

if(acctids.isEmpty() == false){ 
   // no need for the trigger to go any further if the acctids isEmpty

   plmap = ([Select Id, Route_Code__c, ES_Format__c, Account__c from product_configuration__c where recordtypeid = '012g0000000D63W']);
   // no need to run this query until you know it's necessary

   groupedResults = ([Select Account__c, count(Name) From Product_Configuration__c where Account__c in : acctids Group by Account__c]);

}

For(AggregateResult ar : groupedresults) {

      cnt = (Integer) ar.get('expr0');
      acctid = (Id) ar.get('Account__c');
      configmap.put(acctid, cnt);  
} // end For(AggregateResult ar : groupedresults)

For(Product_Configuration__c emd1 : pr2upt) {

   if(plmap.get(emd1.Id).Print_Image__c = true && (configmap.containskey(emd1.Account__c)) )   {
   // I strongly suspect the 2nd test is no longer necessary, but as I'm not familiar with your products, I wouldn't know for certain

      emd1.Print_Image__c = true;
   }

} // end For(Product_Configuration__c emd1 : pr2upt)

update pr2upt;

} // end trigger

Note: above code has not been tested.

12
  • Thanks for posting on SF.SE. Please help the rest of the community by marking this answer as solving your question if it resolved your issue.
    – crmprogdev
    May 28, 2015 at 13:41
  • I am not able to get the code to compile. My understanding is this function must be used with a query. I am talking specifically for where you have AggregateResult[] groupedResults = new AggregateResult[];
    – Zane
    Jun 1, 2015 at 19:46
  • That may have been a typo from copy/pasting, try using list<AggregateResult>groupedResults = new list<AggregateResult>();. It has to be declared outside of the if statement that follows, or it won't compile since the the list won't be recognized as having been declared when used later.
    – crmprogdev
    Jun 1, 2015 at 20:05
  • I am now having an issue with the plmap is being generated as a list. Also, would this cause SOQL limit issues since it's in the for loop? I have tried doing it this way: create a list and reference in the map thus, Map<Id, Product_Configuration__c> plmap = new Map<Id, Product_Configuration__c>(pclist); But I get error: attempt to de-reference a null object where the validation is the final loop.
    – Zane
    Jun 4, 2015 at 16:11
  • Notice that I defined it first at the start of the trigger so that inside the If statement and outside the first For loop, it would already be defined and the query would be created as a map if surrounded by parens as I've done above. Did you do the same? If you did, try changing query line to plmap = new map([SELECT Id, etc....]);
    – crmprogdev
    Jun 4, 2015 at 18:32

You must log in to answer this question.

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