I have created a many to many relationship between two objects, A and B, using a junction object. That works fine, and the related lists show up on A and B with standard layout pages. Is it possible to display fields from object A on object B using this relationship, i.e. using the junction object? How would I reference the fields from A in B on a Visualforce page? Where can I find the name of the relationship?
2 Answers
In my org, I have three objects, Position__c (Master object), Employment_Website__c (Master Object) and Job_Posting__c (Junction object between the two).
If I wanted to display all related Employment Website data for a Position object through a Visualforce page, I would use a page with a standard controller for the Position object. On this page I would loop through the related job posting child objects, and then for each row reference the parent employment website through the parent relationship api name.
Here is an example:
<apex:page StandardController="Position__c">
<apex:sectionHeader title="Position: {!Position__c.Name}"/>
<apex:pageBlock title="Employment Websites">
<apex:pageBlockTable value="{!Position__c.Job_Postings__r}" var="jobPost">
<apex:column value="{!jobPost.Employment_Website__r.Name}"/>
<apex:column value="{!jobPost.Employment_Website__r.Web_Address__c}"/>
<apex:column value="{!jobPost.Employment_Website__r.Price_Per_Post__c}"/>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:page>
I have used a page block table to show the data, but this could be a repeat, or just a plain data table too. If you have a custom controller, you will have to retrieve the fields using some relational SOQL beforehand, but the relationship references remain the same.
The relationship api names are defined on the master-detail field detail page, found on the custom field list on the junction object definition page. Just don't forget to append '__r' and the end of the relationships (replacing '__c' if it exists).
Hope that helps!
In your VF page where you'd like to present object B and related list of A objects, you would need to fetch list of related A objects, but queried with the fields you would like to display.
E.g. let's say you have a ObjectB.page:
<apex:page standardController="B__c" extensions="ObjectBControllerExt" recordSetVar="JunctionObjName">
<h1>Details for {!objB.Name}</h1>
<apex:form>
<apex:pageBlockTable value="ABjunctions" var="ABjunc">
<apex:column value="ABjunc.A__r.Id" />
<apex:column value="ABjunc.A__r.Name" />
<apex:column value="ABjunc.A__r.DateCreated" />
</apex:pageBlockTable>
<apex:form>
</apex:page>
You would have to form your controller to resemble something like:
public with sharing class ObjectBControllerExt {
public B__c objB { get; set; }
public List<A_B__c> ABjunctions { get; set; }
public ObjectBControllerExt(ApexPages.StandardController controller)
{
objB = (B__c)stdController.getRecord();
ABjunctions = [SELECT Id, Name, A__c, A__r.Id, A__r.Name, A__r.Id FROM A_B__c WHERE B__c = :objB];
}
}
Written in rush, but I think it should work.
On a side note, even better solution would be to use an inner class as proxy object - in your case, in the controller constructor you could fetch all the junction objects, iterate over the collection and create fully customized list to suit your needs:
public List<MyInnerClass> listOfAobjects { get; set; }
public ObjectBControllerExt(ApexPages.StandardController controller)
{
objB = (B__c)stdController.getRecord();
ABjunctions = [SELECT Id, Name, A__c, A__r.Id, A__r.Name, A__r.Id FROM A_B__c WHERE B__c = :objB];
listOfAobjects = new List<MyInnerClass>();
for(APN_SRF__c abJunc : ABjunctions) {
listOfAobjects.add(new MyInnerClass(abJunc.A__c));
}
}
public class MyInnerClass {
public string aName { get; set; }
public string aProp1 { get; set; }
public string aProp2 { get; set; }
...
public MyInnerClass(A__c objectA) {
this.aName = objectA.Name;
...
}
}
Of course, in case you would use the solution with inner class as 'proxy object', you'd need to update the bindings in the VF page accordingly. Hope you got the big picture...