In my project we are using fflib_QueryFactory to build queries and also order fields. Example is given below:

fflib_QueryFactory qf = new fflib_QueryFactory(Account.SObjectType)
                      .setCondition( 'name like \'%test%\'').addOrdering('AssetLiability__c.Name',fflib_QueryFactory.SortOrder.DESCENDING);

In above sorting can be done using name on Asset_Liability__c object. As sample test I had written code just to test on how to get relationship field object API name as below:

String sObjectName='Account'; 
String fieldName='AssetLiability__c'; 
Schema.DescribeFieldResult f = Schema.getGlobalDescribe().get(sObjectName).getDescribe().fields.getMap().get(fieldName).getDescribe();

for(Schema.SObjectType reference : f.getReferenceTo()) {
   System.debug('Reference object name: ' + reference.getDescribe().getName());
   System.debug('Reference object label: ' + reference.getDescribe().getLabel());

This gives me correct Object API name (Asset_Liability__c) for relationship field.

When I pass sObjectName as AccountTeamMember and fieldName as User. It throws error attempt to dereference null object. I checked salesforce documentation (https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_accountteammember.htm) for AccountTeamMember there is no User field relationship. But we can build query like below where User.Name is passed:

fflib_QueryFactory qf = new fflib_QueryFactory(AccountTeamMember.SObjectType)
                .selectFields(new List<String>{'UserId', 'User.Name', 'AccountId', 'Account.Name', 'TeamMemberRole'})
                .setCondition('AccountId IN :relatedAccounts')
                .addOrdering('User.Name', fflib_QueryFactory.SortOrder.ASCENDING);

I am facing challenge on understanding how we can pass User.Name in .addOrdering('User.Name', fflib_QueryFactory.SortOrder.ASCENDING); but when I try to get the API name for User on AccountTeamMember using Schema it does not find any field and documentation also does not state any.

1 Answer 1


The simple answer here is that User is not a field, it's the relationship name of the UserId field (which is a field on AccountTeamMember).

The relationship name and the field API name are different things, and you need to be using the field API name when fetching/going through the SObject describe result.

// Prints "User", the relationship name for the UserId field

When we query for fields on related records though (using either plain 'ol SOQL or something like fflib_QueryFactory), we use the relationship name instead of the API name. That's just a design decision that Salesforce made (and I agree with it).

  • Also, looking through the queryfactory code, it seems to me like you should be able to do something like .addOrdering('UserId.Name', fflib_QueryFactory.SortOrder.ASCENDING) because fflib is internally making a call to getFieldPath(), which ends up calling DescribeFieldResult's .getRelationshipName() method. This seems to track with the example code that you gave where you passed AssetLiability__c.Name to the addOrdering() method (whereas if you were to write the query yourself, you'd need to use the relationship name AssetLiability__r.Name instead).
    – Derek F
    Commented Jul 6, 2023 at 14:19

You must log in to answer this question.

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