1
votes

I have a simple SOQL query that returns information relating to a Contact and CampaignMember. I'm attempting to populate a custom object with the results of the SOQL query. However I get the following error when loading the Visualforce page:

Invalid field campaign.name for CampaignMember

List campaignMembers = [select campaign.name, contact.id,contact.firstname, contact.lastname, status, campaignId from CampaignMember where contactId = '003U000000U0eNq' and  campaignId in :campaigns];

for (Integer i = 0; i < campaignMembers.size(); i++) {
    results.add(new CampaignMemberResult(
        (String)campaignMembers[i].get('CampaignId'), 
        (String)campaignMembers[i].get('campaign.name'),
        true
    ));
}

I've ran the SOQL query seperately in the Developer Console and it queries successfully. Why can I not pull in the campaign.name from the SOQL query within the for loop?

1

1 Answers

5
votes

The error you see is caused by the fact you should write it as campaignMembers[i].Campaign.Name. Or if you insist on the getter syntax, campaignMembers[i].getSobject('Campaign').get('Name').

Any special reason you need the wrapper object (or whatever CampaignMemberResult is)? I have strange feeling you're writing too much code to achieve something simple ;) The syntax with campaignMembers[i].Campaign.Name will also mean you don't have to use casts to String.


Plus - if you need to know "in which campaigns does this Contact occur" you have 2 ways:

flat

select contact.id,contact.firstname, contact.lastname, 
    campaignid, campaign.name, 
    status 
from CampaignMember 
where contactId = '003U000000U0eNq'

subquery

From contact you go down to the related list of campaignmembers, then up to campaigns to get their names

SELECT Id, FirstName, LastName,
    (SELECT CampaignId, Campaign.Name FROM CampaignMembers)
FROM Contact WHERE Id = '003U000000U0eNq'

Example how to use "flat" result straight in visualforce (without CampaignMemberResult):

Apex:

public List<CampaignMember> flatMembers {get;set;} // insert dick joke here

flatMembers = [select contact.id,contact.firstname, contact.lastname, 
    campaignid, campaign.name, 
    status 
from CampaignMember 
where contactId = '003U000000U0eNq'];

VF:

<apex:pageBlockTable value="{!flatMembers}" var="cm">
    <apex:column value="{!cm.Contact.LastName}" />
    <apex:column value="{!cm.Status}" />
    <apex:column value="{!cm.Campaign.Name}" />

EDIT

My end goal is a Visualforce page to be displayed on the contact record showing a list of all campaigns with a checkbox alongside each indicating if the contact is a member or not.

You do realize it can quickly grow into a pretty long table? Maybe some filter on campaigns (if you feel like reading about sth advanced - check the documentation for "StandardSetController"). Also I'm pretty sure there are some ways to add Contacts/Leads to Campaigns from Campaign reports - maybe something out of the box would save your time and be more maintainable...

But code solution would be pretty straightforward, start with a helper wrapper class:

public class CampaignWrapper{
    public Boolean selected {get;set;}
    public Campaign c {get; private set;}
    public CampaignWrapper(Campaign c){
        this.c = c;
        selected = !c.CampaignMembers.isEmpty();
    }
}

Then a query and build the list of wrappers:

List<CampaignWrapper> wrappers = new List<CampaignWrapper>();
for(Campaign c : [SELECT Id, Name, (SELECT Id FROM CampaignMember WHERE ContactId = '...')
    FROM Campaign
    LIMIT 1000]){
    wrappers.add(new CampaignMember(c));
}

You should be all set ;) If it's just for displaying - you might not even need the wrapper class (some tricks in visualforce expressions maybe or use Map<Campaign, Boolean> even...

1000 records is the limit of collections passed to Visualforce (10K if your page will be readonly). Past that - pagination, most likely with use with abovementioned StandardSetController.