Fflib: selector Method query giving me error of Duplicate field selected

apexfflibqueryselectorsoql

I have created following method in my Opportunity selector class. I am passing my query fields dynamically from another class.

    public List<Opportunity> selectByDynamicFilter(List<String> lstOfSobjectFields,String strFilter, String strRecordId){
        fflib_QueryFactory query = newQueryFactory().setEnforceFLS(true).assertIsAccessible();
        query.selectFields(lstOfSobjectFields);
        query.setCondition(strFilter);
        return (List<Opportunity>)Database.Query(query.toSOQL());
    }

this is how my getSObjectFieldList method in selector looks like:

   public List<Schema.SObjectField> getSObjectFieldList()
   {
       return new List<Schema.SObjectField>{
           Opportunity.Id,
           Opportunity.Name,
           Opportunity.rbcpcb_LeadProductorServiceFamily__c,
           Opportunity.rbcpcb_ProductCategory__c,
           Opportunity.StageName,
           /** API names of fields which needs to be queried */
       };
   }

Here is my Problem: if I pass any fields that already exist in getSObjectFieldList to my newly created method it's giving me: System.QueryException: duplicate field selected: 'fieldX'

So I Guess, it's not doing dynamic query, query adding all the fields exist in getSObjectFieldList.

Note: issue is not happening for Name field but for StageName, rbcpcb_ProductCategory__c & rbcpcb_LeadProductorServiceFamily__c.

Best Answer

You have:

public List<Opportunity> selectByDynamicFilter(List<String> lstOfSobjectFields,String strFilter, String strRecordId){
    fflib_QueryFactory query = newQueryFactory().setEnforceFLS(true).assertIsAccessible();
    query.selectFields(lstOfSobjectFields);
    query.setCondition(strFilter);
    return (List<Opportunity>)Database.Query(query.toSOQL());
}

The method

fflib_QueryFactory query = newQueryFactory()

has an optional argument includeSelectorFields that allows you to not use the selector's default fields.

Here is the code in fflib_SObjectSelector

/**
 * Returns a QueryFactory configured with the Selectors object, fields, fieldsets and default order by
 **/
public fflib_QueryFactory newQueryFactory()
{    
    return newQueryFactory(m_enforceCRUD, m_enforceFLS, true);
}

/**
 * Returns a QueryFactory configured with the Selectors object, fields, fieldsets and default order by
 **/
public fflib_QueryFactory newQueryFactory(Boolean includeSelectorFields)
{    
    return newQueryFactory(m_enforceCRUD, m_enforceFLS, includeSelectorFields);
}

so, you can do the following:

public List<Opportunity> selectByDynamicFilter(List<String> lstOfSobjectFields,String strFilter, String strRecordId){
    fflib_QueryFactory query = newQueryFactory(false) // <= false means don't include getSobjectFieldList
           .setEnforceFLS(true).assertIsAccessible();
    query.selectFields(lstOfSobjectFields);
    query.setCondition(strFilter);
    return (List<Opportunity>)Database.Query(query.toSOQL());
}

Now, if you want a mix of default fields and caller-supplied fields, you'll need to use the false argument and a set to dedup between the caller-supplied fields and the fields returned by getSobjectFieldList. This will be easier if the caller supplied fields is a collection of SObjectField, not a collection of Strings

Related Topic