+ Start a Discussion
Kelly KKelly K 

Dynamically assign values to multiple generic fields and use 1 DML statement

Hi All,

This article has been helpful on getting me started: http://salesforce.stackexchange.com/questions/4193/update-a-records-using-generic-fields 

For my application I'm trying update several fields on a contract based on the products that are selected on an opportunity.  I'm using a crosswalk object that has information on which field to update and with what kind of value. Here's a snippet of the code I'm working with and I know it works:

//Update Opportunity Products & Opportunity
  for(Opportunity opportunity : opportunitiesMap.values()) {
   //Update Opportunity with Contract Number
   Opportunity opportunityForUpdate = new Opportunity(Id = opportunity.Id, Contract_Number__c = opportunityToContractMap.get(opportunity.Id).Id);
   opportunitiesToUpdate.add(opportunityForUpdate);

   //Update Opportunity Products with Contract Number
   for(OpportunityLineItem oppProduct : opportunitiesToProductsMap.get(opportunity.Id)) {
    oppProduct.Contract_Number__c = opportunityToContractMap.get(opportunity.Id).Id;
    productsToUpdate.add(oppProduct);

    for(Product_to_Contract_Matrix__c p2cm : productsToMatrixMap.get(oppProduct.PriceBookEntry.Product2Id)) {
     Schema.SObjectField currentField = contractFields.get(p2cm.Contract_Field_to_Update__c);
     Contract contract = new Contract(Id = opportunityToContractMap.get(opportunity.Id).Id);

     if(p2cm.Update_Type__c == 'Text')
      contract.put(currentField, p2cm.Update_Value_With__c);
     else if(p2cm.Update_Type__c == 'Date')
      contract.put(currentField, system.today());
     else if(p2cm.Update_Type__c == 'Rate (String)')
      contract.put(currentField, String.valueOf(oppProduct.UnitPrice));
     else if(p2cm.Update_Type__c == 'Rate (Numeric)')
      contract.put(currentField, oppProduct.UnitPrice);
     //contractsToUpsert.put(contract.Id, contract);
     upsert contract;
    }
   }
  }

Problem is that the DML statement to update the contract is 3 for loops in and can potentially end up updating upwards of 30 to 50 fields for one contract record - easily hitting governor limits. I tried assigning it to a list as you can see with the commented out line just above, but I found that I using this method overwrites the previous field update in the loop.

Does anyone have any thoughts on how I can modify my code to where I only need 1 DML statement and still apply all the updates to my contract record?

Much appreciated!
Kelly KKelly K
Never mind... seems all I needed to do was move my contract assigment a loop up:

//Update Opportunity Products & Opportunity
  for(Opportunity opportunity : opportunitiesMap.values()) {
   //Update Opportunity with Contract Number
   Opportunity opportunityForUpdate = new Opportunity(Id = opportunity.Id, Contract_Number__c = opportunityToContractMap.get(opportunity.Id).Id);
   opportunitiesToUpdate.add(opportunityForUpdate);

   //Update Opportunity Products with Contract Number
   for(OpportunityLineItem oppProduct : opportunitiesToProductsMap.get(opportunity.Id)) {
    oppProduct.Contract_Number__c = opportunityToContractMap.get(opportunity.Id).Id;
    productsToUpdate.add(oppProduct);

    Contract contract = new Contract(Id = opportunityToContractMap.get(opportunity.Id).Id);

    for(Product_to_Contract_Matrix__c p2cm : productsToMatrixMap.get(oppProduct.PriceBookEntry.Product2Id)) {
     Schema.SObjectField currentField = contractFields.get(p2cm.Contract_Field_to_Update__c);    

     if(p2cm.Update_Type__c == 'Text')
      contract.put(currentField, p2cm.Update_Value_With__c);
     else if(p2cm.Update_Type__c == 'Date')
      contract.put(currentField, system.today());
     else if(p2cm.Update_Type__c == 'Rate (String)')
      contract.put(currentField, String.valueOf(oppProduct.UnitPrice));
     else if(p2cm.Update_Type__c == 'Rate (Numeric)')
      contract.put(currentField, oppProduct.UnitPrice);
    
     contractsToUpsert.put(contract.Id, contract);
     //upsert contract;
    }
   }