2

I'm attempting to rollup some Activity data to Campaign Members from a Trigger event. I've already worked through my trigger/filtering logic and now I have a list of affected campaign members:

List<CampaignMember> campaign_members = CampaignUtils.listCampaignMembersByWhoId(whoId_list); /* 1 SOQL */

As well as a list of Recent Activities per Lead/Contact (which is the WhoId):

List<ActivityHistory> recent_activities = CampaignUtils.fetchRecentActivityForCampaginMembers(campaign_members,true);

*Example Instance: 20+ activities are updated, between 3 Leads/Contacts, producing 6 Campaign Members affected =List<CampaignMember> campaign_members, as well as 3 recent activities, (1 per Who [ContactId/LeadId]) =List<ActivityHistory> recent_activities

So with these 2 list I need to merge or update the campaign_members fields with data in the recent_activities. For example:

campaign_members.F2F_Activity_Date__c = recent_activities.ActivityDate

BUT, this is based on matching WhoId(s). I'm thinking I need a loop of some sort but not sure how to say, for each campaign_members find the matching recent_activity, and then add that activity data to this member.

Thanks in advance for any help!

EDIT: My current attempt looks something like this

for (CampaignMember member : campaign_members) {
    for(ActivityHistory act : recent_activities){
        if (act.WhoId == member.LeadId || act.WhoId == member.ContactId) {
            campaign_members.get(**THIS MEMBER**).F2F_Activity_ID__c = act.Id;
            campaign_members.get(member).custom_field__c = act.value;
        }
    }
}
update campaign_members;
  • What object is the trigger on? – Bradley Delaune Jan 16 '15 at 21:07
  • One on Task and Event because those make up Activities in SF. Does that matter for this though? – Xtremefaith Jan 16 '15 at 21:08
  • It matters, I'm just still trying to wrap my head around what you are trying to do so I can answer the question. Sorry! – Bradley Delaune Jan 16 '15 at 21:20
  • No worries just making sure. The goal is when an activity is inserted or updated to rollup details (recent activity details, number of activities, etc.) to the campaign member objects for any Lead/Contact that is part of an active campaign during that activity – Xtremefaith Jan 16 '15 at 21:23
  • I guess I still don't 100% get it, but I can try. Are you having trouble finding the Activity that matches with the CampaignMember? I bet it's because there could potentially be more than 1 activity per CampaignMember – Bradley Delaune Jan 16 '15 at 21:40
3

In your example you provided, you are very close. The only thing you need to understand is that in the Java world (and therefore the Apex world), any non-primitive data types are pass-by-reference. Your example will look something like this to work:

Map activityMap = new Map();
for (ActivityHistory act: recent_Activities) {
  activityMap.put(act.WhoId,act);
}

for (CampaignMember member : campaign_members) {
    if(activityMap.containsKey(member.ContactId)){
        member.F2F_Activity_ID__c = activityMap.get(member.ContactId).Id;
        member.custom_field__c = activityMap.get(member.ContactId).value;
    }
}
update campaign_members;

In addition to fix the issue you will also want to prevent the nested for loops. You'll see how I used a Map to prevent that.

| improve this answer | |
  • -1 While you technically answered the question, you avoided the real problem, which is the performance bottleneck that will occur from using a nested loop like this. – sfdcfox Jan 17 '15 at 0:02
  • @sfdcfox I agree. I helped him on chat with that as well. I suppose I should update my answer with the performance enhancements as well? – Bradley Delaune Jan 17 '15 at 0:02
  • Your answer looks much better now! – sfdcfox Jan 17 '15 at 0:18
  • Thanks! Still relatively new to stack exchange and tend to forget where to put information. – Bradley Delaune Jan 17 '15 at 0:20
4

You should avoid nested loops and use a Map instead. Since WhoId is not unique among your ActivityHistory records, you should ideally use Map<Id, List<ActivityHistory>>, but in this case it looks like you will arbitrarily pick which ActivityHistory to use, so Map<Id, ActivityHistory will probably suffice.

static void updateCampaignMembers(List<CampaignMember> campaign_members, List<ActivityHistory> recent_activities)
{
    Map<Id, ActivityHistory> whoIdToHistory = new Map<Id, ActivityHistory>();
    for (ActivityHistory history : recent_activities)
    {
        whoIdToHistory.put(history.WhoId, history);
    }

    for (CampaignMember member : campaign_members)
    {
        ActivityHistory leadMatch = whoIdToHistory.get(member.LeadId);
        ActivityHistory contactMatch = whoIdToHistory.get(member.ContactId);
        if (leadMatch != null) mergeValues(member, leadMatch);
        if (contactMatch != null) mergeValues(member, contactMatch);
    }
    update campaign_members;
}

static void mergeValues(CampaignMember member, ActivityHistory history)
{
    if (history == null) return;
    member.F2F_Activity_ID__c = history.Id;
    member.custom_field__c = history.value;
}
| improve this answer | |

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.