1

I am trying to write a trigger that will update a look up field on the CampaignMemeber when it finds a matching record on Marketing_KPI_Target__c.

The code saves but does not update anything not sure what I am missing.

trigger CampaignMemberTrigger on CampaignMember (after insert, after update) {
    // Get a list of fields from the sObject Marketing_KPI_Target__c and name the list kpiTargetList
    List<Marketing_KPI_Target__c> kpiTargetList = [SELECT Type_of_Sale__c, ECI_Product__c, CurrencyIsoCode,KPI_Target_Date__c FROM Marketing_KPI_Target__c];
    List<CampaignMember> cmlis =[SELECT id, Type_of_Sale__c, ECI_Product__c, Currency__c,Response_Tracking_Date__c,HasResponded FROM CampaignMember WHERE Id IN: Trigger.newMap.keySet()];
        for (CampaignMember member : cmlis) {
         for (Marketing_KPI_Target__c kpiTarget : kpiTargetList) {
             if (kpiTarget.Type_of_Sale__c == member.Type_of_Sale__c &&
                kpiTarget.ECI_Product__c == member.ECI_Product__c &&
                kpiTarget.CurrencyIsoCode == member.Currency__c &&
                member.Response_Tracking_date__c != Null &&
                kpiTarget.KPI_Target_Date__c.month() == member.Response_Tracking_Date__c.month() &&
                kpiTarget.KPI_Target_Date__c.year() == member.Response_Tracking_Date__c.year() &&
                member.HasResponded == True
                )
            {
                 member.Marketing_KPI_Target__c = kpiTarget.Id;
                 continue;
            }
        }
    }
}
2
  • 1
    If you are setting this field on CampaignMember then trigger event should be before insert and before update.
    – Devendra
    Aug 24 '16 at 19:18
  • 1
    What @Devendra said. Also you don't need to query the records, just use Trigger.new.
    – dBeltowski
    Aug 24 '16 at 20:20
1

As Derek said you need to change your Trigger from after insert/after update to before insert/before update. This will allow you to update the Campaign Member records directly and you won't need to query them.

Replace your SOQL query with Trigger.new to get the list of Campaign Members to operate on.

trigger CampaignMemberTrigger on CampaignMember (after insert, after update) {
    // Get a list of fields from the sObject Marketing_KPI_Target__c and name the list kpiTargetList
    List<Marketing_KPI_Target__c> kpiTargetList = [SELECT Type_of_Sale__c, ECI_Product__c, CurrencyIsoCode,KPI_Target_Date__c FROM Marketing_KPI_Target__c];
    List<CampaignMember> cmlis =Trigger.new;
        for (CampaignMember member : cmlis) {
         for (Marketing_KPI_Target__c kpiTarget : kpiTargetList) {
             if (kpiTarget.Type_of_Sale__c == member.Type_of_Sale__c &&
                kpiTarget.ECI_Product__c == member.ECI_Product__c &&
                kpiTarget.CurrencyIsoCode == member.Currency__c &&
                member.Response_Tracking_date__c != Null &&
                kpiTarget.KPI_Target_Date__c.month() == member.Response_Tracking_Date__c.month() &&
                kpiTarget.KPI_Target_Date__c.year() == member.Response_Tracking_Date__c.year() &&
                member.HasResponded == True
                )
            {
                 member.Marketing_KPI_Target__c = kpiTarget.Id;
                 continue;
            }
        }
    }
}
0
4

Generally speaking, when you want to update records of a given sObject in a trigger on the same sObject, you should be running the trigger on a before event like Before Update.

This is advice that comes from the developer docs on Triggers. The relevant excerpt being

There are two types of triggers:

  • Before triggers are used to update or validate record values before they’re saved to the database.
  • After triggers are used to access field values that are set by the system (such as a record's Id or LastModifiedDate field), and to affect changes in other records, such as logging into an audit table or firing asynchronous events with a queue. The records that fire the after trigger are read-only.

In a Before Update trigger, you won't need to run a DML call like update <some list of records>; if you make changes to the record that exists in either the Trigger.new or Trigger.newMap trigger context variables.

To get your trigger working more along the lines that you expect, I'd do the following:

  • Change your trigger to run Before Insert and Before Update
  • Get rid of your query for CampaignMembers, you don't need it
  • Change for (CampaignMember member : cmlis) to for (CampaignMember member : Trigger.new)
3
  • Here is the new code and there is one problem. When adding a new record to the CampainMember object the trigger will not fire even if it meets all the criteria. If I just resave the record the trigger works fine. Any way around this problem I am not sure where to start. I changed the For loop to this ' for (CampaignMember member : Trigger.New) { for (Marketing_KPI_Target__c kpiTarget : kpiTargetList) { '
    – Jeremy
    Aug 24 '16 at 19:49
  • FYI you can add an authoritative reference to why OP should use before triggers here.
    – Adrian Larson
    Aug 24 '16 at 20:12
  • @Jeremy How are you testing this? Are you sure that you have some KPI records in place? Are you sure that the CampaignMembers that you're inserting or updating match all of the requirements in your trigger?
    – Derek F
    Aug 24 '16 at 20:34

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.