I have a trigger that when a campaign member record is created or updated it will write the campaign ID to a field either on the Lead or Contact.
I started with this code but it was not Bulkifed as my SOQL was inside a FOR.
trigger CurrentCampaign on CampaignMember (before insert, before update) {
List<Lead> newLeads = new List<Lead>();
List<Contact> newContacts = new List<Contact>();
for(CampaignMember cm : Trigger.new){
if(cm.LeadId != Null && cm.ContactId == Null){
List<Lead> lu = [SELECT Id, Current_Campaign__c FROM Lead
WHERE Id = :cm.LeadId];
if (lu.size() > 0) {
for(Integer i = 0; i < lu.size(); i++){
lu[i].Current_Campaign__c = cm.CampaignId;
newLeads.add(lu[i]);
}
}
}
else if(cm.ContactId != Null){
List<Contact> cu = [SELECT Id, Current_Campaign__c From Contact
WHERE Id =:cm.ContactId];
if (cu.size() > 0) {
for(Integer i = 0; i < cu.size(); i++){
cu[i].Current_Campaign__c = cm.CampaignId;
newContacts.add(cu[i]);
}
}
}
}
Upsert newLeads;
Upsert newContacts;
}
So after fumbling around I got it down to this.
trigger CurrentCampaign on CampaignMember (before insert, before update) {
List<Lead> newLeads = new List<Lead>();
List<Contact> newContacts = new List<Contact>();
for(CampaignMember cm : Trigger.new){
if(cm.LeadId != Null && cm.ContactId == Null){
cm.Lead.Current_Campaign__c = cm.CampaignId;
newLeads.add(cm.Lead);
}
else if(cm.ContactId != Null){
cm.Contact.Current_Campaign__c = cm.CampaignId;
newContacts.add(cm.Contact);
}
}
Upsert newLeads;
Upsert newContacts;
}
Then I got this test.
@isTest
public class currentCampaignTest{
static testMethod void CurrentCampaign(){
Account testAccount = new Account(Name = 'Testy McTesterson');
Contact testContact = new Contact(FirstName = 'TestyMc' , LastName = 'Testerson', Title = 'TestyMcTesting' , Email = '[email protected]');
Lead testLead = new Lead(LastName = 'TestyMcTesterson' , Company = 'Nowaythistestcanmatchanything');
Campaign testCampaign = new Campaign(Name = 'TestingMcTesterson Campaign', IsActive = TRUE);
insert testAccount;
insert testContact;
insert testLead;
insert testCampaign;
CampaignMember cm0 = new CampaignMember(CampaignId = testCampaign.Id, ContactId = testContact.Id, LeadId = NULL, Status ='Sent');
CampaignMember cm1 = new CampaignMember(CampaignId = testCampaign.Id, ContactID = NULL , LeadId = testLead.Id, Status ='Sent');
insert cm0;
insert cm1;
List<CampaignMember> cm2 = [SELECT id, Status FROM CampaignMember LIMIT 201];
for(Integer i=0; i<cm2.size(); i++){
cm2[i].Status = 'Responded';
}
update cm2;
}
}
Now I keep getting this error when I run the test.
Error Message System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, CurrentCampaign: execution of BeforeInsert
caused by: System.NullPointerException: Attempt to de-reference a null object
Trigger.CurrentCampaign: line 14, column 1: []
Stack Trace Class.currentCampaignTest.CurrentCampaign: line 20, column 1
I understand this is when you try and reference something that hasn't been set yet but on Line20 of the test I am trying to insert a new CampaignMember with a Null LeadID. This seems to fail at "cm.Contact.Current_Campaign__c = cm.CampaignId" when I try and reference the Contact related to the CampaignMember Record.
I am still pretty new to all this Apex and coding base and I can't figure out why it wont insert the record.
cm.Contact.current_campaign__c
- you need to query for the parents in the trigger. Trigger.new only knows about the fields inCampaignMember
. (2) For clarity - delete the non bulkified code.contactIdToContactMap
, andleadIdToleadMap
that you build from one SOQL query each. Then you have all you need. The Contacts and Leads you pull in are only the ones referenced in the cm.leadId or cm.contactId fields. Very efficient.