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?
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.