1

Hello I am fairly new to Apex and still learning a lot. I have got stuck with an issue that I cannot figure out how to resolve, I have looked at several articles and answers to similar questions but I still can't quite figure this out and I am hoping someone can point out what I am doing wrong here.

I am trying to display a list of contact details on a record page for a custom object. The object has an Account as its parent and I want to pull Contact details for contacts related to that account via the AccountContactRelation object.

I have created some Apex and Visualforce but I keep getting errors from the Apex:

Illegal Conversion from List to List

I think understand why I am getting the error; I need to make sure I am using a single unique value for Account ID, but I cannot work out how to resolve the problem. Here is what I have

Apex

public class MyObjectContactList {
    public String currentRecordId {get;set;}
    public Static String AccountRecordId {get; set;}

    public List<AccountContactRelation> getaccountcontacts() {
        currentRecordId = ApexPages.CurrentPage().getparameters().get('id'); 
        AccountRecordId = [SELECT Account__c FROM MyObject__c WHERE ID = :currentRecordId LIMIT 1];
 
        return [SELECT Name, Phone, Email
                           FROM Contact
                           WHERE ID IN(
                           SELECT ContactId
                           FROM AccountContactRelation
                           WHERE AccountId = :AccountRecordId)];
    }
}

VF

<apex:page standardcontroller="MyObject__c" extensions="MyObjectContactList">
    <apex:pageBlock >
        <apex:pageBlockTable value="{!Records}" var="Record">
            <apex:column >
                <apex:facet name="header">Name</apex:facet>
                <apex:outputText value="{!Record.Name}"/>
            </apex:column>
            <apex:column >
                <apex:facet name="header">Phone</apex:facet>
                <apex:outputText value="{!Record.Phone}"/>
            </apex:column>
            <apex:column >
                <apex:facet name="header">Email</apex:facet>
                <apex:outputText value="{!Record.Email}"/>
            </apex:column>
        </apex:pageBlockTable>
    </apex:pageBlock>
</apex:page>
1
  • I've taken the liberty of formatting your question for you. I also made some slight changes to your syntax to make it valid enough to produce the error that you're reporting.
    – Derek F
    Jan 27, 2023 at 15:26

1 Answer 1

2

Your getAccountContacts() method has a defined return type of List<AccountContactRelation>

Inside that method, you're returning the result of a query on the Contact SObject (i.e. the SObject specified in the top-level FROM of the query), which is a List<Contact>

Since Contact isn't a subtype of AccountContactRelation, you get your error (the more complete error would be Illegal Conversion from List<Contact> to List<AccountContactRelation> but Salesforce is treating the stuff inside <> as an HTML tag and not rendering that part). The Contact and AccountContactRelation types are not compatible.

To resolve this, you'll need to change your query to be based on AccountContactRelation.

// ACR is a "junction object"
// It has master-detail relationships to 2 other objects (Account and Contact)
// We can access data on a "parent" record (ACR is the "child" record in the hierarchy)
//   by using dot notation
// Standard relationships usually end in "Id", dropping that "Id" gives you the
//   "relationship name", which is what you use to query (and later access) data on
//   parent objects
// For custom master-detail or lookup fields, the field name would be something like
//   "opportunity__c", and you'd just change the "__c" to "__r" to query/access parent
//   data
return [
    SELECT Contact.Name, Contact.Phone, Contact.Email
    FROM AccountContactRelation
    WHERE AccountId = :AccountRecordId
];

This also means that you'll need to adjust your Visualforce page to use the same dot-notation to traverse from the ACR record you're working with to the Contact (where the information you want lives)

<!--
  The "value" needs to match a property name, or be the name of
    a getter method in your controller (without the "get" portion)
-->
<apex:pageBlockTable value="{!AccountContacts}" var="Record">
<!--
  Access data using dot notation, pretty similar to how you would in Apex
    and how you do in your query
-->
<apex:outputText value="{!Record.Contact.Name}"/>

+edit:

Missed another issue that was brought up in a comment.

AccountRecordId = [SELECT Account__c FROM MyObject__c WHERE ID = :currentRecordId LIMIT 1];

This is a problem because accountRecordId1 is defined as a String.

SOQL queries always return a List<SObject> (a List<MyObject__c> in your case. MyObject__c is a subtype of SObject). Salesforce allows us to assign the result of a query to a single SObject instance as a quality-of-life thing, but it only works:

  • When your query returns exactly 1 row (0 or 2+ rows cause errors)
  • When you put the result into an SObject (or whatever specific SObject your query returns, like MyObject__c)

A String is not an SObject, so that's an issue.

Keeping in mind that the result of a query is always a List, you could index into it and pull the Id out that way

accountRecordId = [<your query here>][0].Account__c;

but that runs into an issue if your query returns no rows.

The safe way to handle queries is to always store the result in a List. That allows you to check whether or not it's empty before trying to work on it (and a query will never return null. If you get 0 rows, you'll get an empty list as the result).

// plural names for collections (lists, sets, maps) is another convention
List<MyObject__c> myObjectRecs = [SELECT Account__c FROM MyObject__c WHERE ID = :currentRecordId LIMIT 1];

// Handle the case where there is no Account so we don't need to think about it
//   later in code
if(myObjectRecs.isEmpty()){
    return new List<AccountContactRelation>();
}

accountRecordId = myObjectRecs[0].Account__c;

return [
    SELECT Contact.Name, Contact.Phone, Contact.Email
    FROM AccountContactRelation
    WHERE AccountId = :AccountRecordId
];

1: Apex is largely case-insensitive (Sets and the keys of Maps being the notable exceptions), but sticking to guidlines like "Class names start with an upper-case letter" and "methods and variables start with a lower-case letter" is a good idea for we lowly humans

5
  • Thank you very much! Your explanation is very thorough and has helped me a lot. I made the change you suggested to the Apex, I now get a different error on the line of the code where I am getting my Account ID. 'Illegal assignment from List<MyObject__c> to String' Related to AccountRecordId = [SELECT Account__c FROM Adviser__c WHERE ID = :currentRecordId LIMIT 1]; I tried to fix this by adding LIMIT 1 at the end, but this hasn't worked. Do you know how I get around this?
    – T_D_GP33
    Jan 27, 2023 at 16:51
  • @T_D_GP33 D'oh, I missed that one. Updated my answer.
    – Derek F
    Jan 27, 2023 at 17:08
  • Thanks so much for your help with this. I do feel like I am going around in circles though; all I seem to be able to do is change the error message I am getting. I still get an error on this line List<Account> accounts = [SELECT Account__c FROM MyObject__c WHERE ID = :currentRecordId LIMIT 1]; it is just the new error is Illegal assignment from List<MyObject__c> to List<Account> I searched for this error but I don't see an explanation that seems to work in my case. One post suggests using another name not accounts as it is reserved, but I tried this and it made no difference.
    – T_D_GP33
    Jan 29, 2023 at 11:10
  • @T_D_GP33 I had made yet another mistake, which is now fixed. The thing to take away from this is that type compatibility is important. When you assign a value to a variable, the type on the left-hand side (LHS) needs to be compatible with the type on the right-hand side (RHS). List<Account> = List<MyObject> doesn't work. List<MyObject> = List<MyObject> does. This is the same reason why String accountRecordId = [<query here>] didn't work. The LHS type (String) is not compatible with the RHS type (List<MyObject>). Type compatibility is driven by inheritance (an Object-Oriented thing)
    – Derek F
    Jan 29, 2023 at 13:30
  • Thank you so much for your help with this. I have now got this working. I actually made another mistake in the VF which I resolved by amending <apex:page standardcontroller="MyObject__c" extensions="MyObjectContactList"> to <apex:page Controller="MyObjectContactList">
    – T_D_GP33
    Jan 29, 2023 at 13:48

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .