2

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.

1
  • Welcome to SFSE. I would recommend taking this to the Discussions section of the GitHub repo for FFLib (github.com/apex-enterprise-patterns/fflib-apex-common/…), you'll likely get more framework-specific answers there. I've used FFLib before but never encountered this problem as was not passing fields dynamically. I'd guess that it's not designed to support that duplicate check (today), but may be a good enhancement. Commented May 3 at 19:59

2 Answers 2

3

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

2

I would recommend taking this to the Discussions section of the GitHub repo for FFLib (https://github.com/apex-enterprise-patterns/fflib-apex-common/discussions), you'll likely get more framework-specific answers there. I've used FFLib before but never encountered this problem as was not passing fields dynamically. I'd guess that it's not designed to support that duplicate check (today), but may be a good enhancement.

The only programmatic alternative I could suggest would be that you need to do the check & deduplication yourself inside of your selectByDynamicFilter method, something like:

public List<Opportunity> selectByDynamicFilter(List<String> lstOfSobjectFields,String strFilter, String strRecordId){
    fflib_QueryFactory query = newQueryFactory().setEnforceFLS(true).assertIsAccessible();
    List<Schema.SObjectField> defaults = getSObjectFieldList();

    // Split your list (lstOfSobjectFields) by a delimiter to get the dynamic field list.

    List<String> dedupedQueryList = new List<String>();
    for(Schema.SObjectField field : defaults){
        // Compare each field with the split list, 
        // identifying duplicates
        if(isMatch){
            dedupedQueryList.add(field.getDescribe().getName());
        }
    }

    //Then build a new query string with the dedupedQueryList,
    // and query with the deduplicated string
    query.selectFields(lstOfSobjectFields);
    query.setCondition(strFilter);
    return (List<Opportunity>)Database.Query(query.toSOQL());
}

Or you can branch your own version of FFLib and add this support to the framework.

You must log in to answer this question.

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