2

Pretty new to this and I am creating a Visualforce page that returns a list of contacts that belong to the logged in user. I have the following controller but when I preview the page I get the

error unexpected token: '('

Controller

public class ContactsListController {
    
    private String sortOrder = 'LastName';
   public List<Contact> getContacts() {
    
    List<Contact> results = Database.query(
        'SELECT Id, FirstName, LastName, Title, Email, OwnerId ' +
        'FROM Contact ' +
        'WHERE OwnerId =:UserInfo.getUserId()' +
        'ORDER BY ' + sortOrder + ' ASC ' +
        'LIMIT 10'
    );
    
        return results;
    
    }
}

Visualforce page

<apex:page controller="ContactsListController">
    <apex:form >
        <apex:pageBlock title="Contacts List" id="contacts_list">
            <apex:pageBlockTable value="{! contacts}" var="ct">
                <apex:column value="{!ct.FirstName}"/>
                <apex:column value="{! ct.LastName}"/>
                <apex:column value="{! ct.Title}"/>
                <apex:column value="{! ct.Email}"/>  
                <apex:column value="{! ct.OwnerId}"/>  
            
            </apex:pageBlockTable>
        </apex:pageBlock>
    </apex:form>   
    
</apex:page>

3 Answers 3

0

To make it works you need to create String userId variable and then use it in a query !
So it will look like this :

public class ContactsListController {
    private String sortOrder = 'LastName';
    public List<Contact> getContacts() {
       String userId = UserInfo.getUserId();
       List<Contact> results = Database.query(
           'SELECT Id, FirstName, LastName, Title, Email, OwnerId ' +
           'FROM Contact ' +
           'WHERE OwnerId =: userId ' +
           'ORDER BY ' + sortOrder + ' ASC ' +
           'LIMIT 10'
       );
       return results;

   }
}
0

Add with sharing keyword while declaring a class. So your class should be

public class **with sharing** ContactsListController {
    private String sortOrder = 'LastName';
    public List<Contact> getContacts() {
       String userId = UserInfo.getUserId();
       List<Contact> results = Database.query(
           'SELECT Id, FirstName, LastName, Title, Email, OwnerId ' +
           'FROM Contact ' +
           'ORDER BY ' + sortOrder + ' ASC ' +
           'LIMIT 10'
       );
       return results;

   }
}

This will return all the contacts where the logged-in user is either owner or the record is shared with that user.

0

This is a limitation of using Dynamic SOQL

The reason we need to execute UserInfo.getUserId() prior to running the query is that dynamic SOQL (which is where you pass a query string into Database.query()) can't evaluate complex variable binds.

With dynamic soql, we basically can't use any dots in a variable bind. So things like UserInfo.getUserId() and myAccount.Id would be invalid.

You can get around this in one of two ways (with dynamic SOQL):

  • Execute UserInfo.getUserId() before the query, and store the result in a variable. You can then use that intermediate variable in a bind (as in Vitalii Dehnerys's and Balwinder Kumar's answers)
  • Calculate the value while you're building your query string, and enclose it in single quotes

Since the other two answers cover the first option, I'll cover the second one.

Doing this without variable binds

In a nutshell, instead of
'WHERE OwnerId =:UserInfo.getUserId()'

you could do
'WHERE OwnerId = \'' + UserInfo.getUserId() + '\''

If you were to print the resulting query to the debug log, it'd end up looking like
WHERE OwnerId = '005000000000001'

Just the same as if it weren't a dynamic query (with the string value enclosed in quotes). Those extra \' were necessary here to add the single quotes. It's a bit of a pain to do things this way, which is why most people use variable binds.

There is an easier way

You don't need to be using dynamic SOQL here. Since the only part of the query that involves run-time data is a value that you're comparing against in the WHERE clause, you can just execute the query using the static [SELECT X FROM Y WHERE Z] query approach.

public List<Contact> getContacts() {
    // Static queries can 
    // 1: Span multiple lines just fine
    // 2: Use complex variable binds (things that need dot-notation)
    return [SELECT Id, FirstName, LastName, Title, Email, OwnerId
            FROM Contact
            WHERE OwnerId = :UserInfo.getUserId()
            ORDER BY LastName ASC
            LIMIT 10];
}

Though if you have an eye on making this more dynamic...

Something like changing the fields that you're querying, choosing one of many objects to query against, or changing the field that you're ordering by, then using dynamic SOQL makes sense.

My currently preferred method for building dynamic query strings is to use String.format(). I find that it's easier to read and maintain than a bunch of string concatenation. It allows us to use numbered placeholders, which get substituted by the List<String> or List<Object> that we pass in as the second parameter.

Applied to your example

public class ContactsListController {
    // The {get; set;} turn the variable into a "property"
    // It tells Salesforce to create/use a default getter and setter
    //   so that we can use this in Visualforce.
    // Without this, you would need to manually create `getSortOrder()` 
    //   and `setSortOrder(String input)` to use this in Visualforce
    // The downside of using the automatic getter/setter is that it's
    //   a bit of a pain to set a default value
    public String sortField {get; set;}

    // ...but we can just set the default value in a constructor
    public ContactsListController(){
        sortField = 'LastName';
    }

    public List<Contact> getContacts() {
        String queryString = String.format(
            // I'm going a bit overboard here, but it is useful to show
            //   how you can (fairly easily) defer the decision of which fields,
            //   object, and filters you use until runtime
            'SELECT {0} FROM {1} WHERE {2} ORDER BY {3} LIMIT 10',
            new List<String>{
                // 0th placeholder here = fields
                // You could just pass a string like 'Id, FirstName, LastName, ...'
                //   but if you're dynamically selecting fields, then you probably
                //   have a List<String>.
                // You can use String.join(list, separator) to turn it into a single string
                String.join(new List<String>{'Id', 'FirstName', 'LastName', 'Title', 'Email', 'OwnerId'}, ', '),
                // 1st placeholder for us = object name
                'Contact',
                // 2nd placeholder for us = filters
                // You could also use String.join() here if you have multiple filters
                'OwnerId = \'' + UserInfo.getUserId() + '\'',
                // 3rd placeholder for us = ordering field
                sortField + ' ASC'
            }
        );

        List<Contact> results database.query(queryString);
        return results;
    }
}

with the comments removed

public class ContactsListController {
    public String sortField {get; set;}

    public ContactsListController(){
        sortField = 'LastName';
    }

    public List<Contact> getContacts() {
        String queryString = String.format(
            'SELECT {0} FROM {1} WHERE {2} ORDER BY {3} LIMIT 10',
            new List<String>{
                String.join(new List<String>{'Id', 'FirstName', 'LastName', 'Title', 'Email', 'OwnerId'}, ', '),
                'Contact',
                'OwnerId = \'' + UserInfo.getUserId() + '\'',
                sortField + ' ASC'
            }
        );

        List<Contact> results database.query(queryString);
        return results;
    }
}

You must log in to answer this question.

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