-
Notifications
You must be signed in to change notification settings - Fork 23
14) Implementing the Selector Layer with the Apex Common Library
Every Selector layer class you create should at least implement the following methods for it to work as anticipated.
//Selector layer classes should all use the inherited sharing keyword so that the caller determines to context it operates in.
//It should also always extend the fflib_SObjectSelector so it can inherit that classes methods and functionality.
public inherited sharing class Contact_Selector extends fflib_SObjectSelector
{
public Contact_Selector(){
/*This is calling the fflib_SObjectSelector classes constructor and setting the following booleans:
1) If the selector queries should use field sets
2) If you would like to enforce CRUD security
3) If you would like to enforce FLS
4) If you would like to sort selected fields
*/
super(false, true, true, false);
}
//Add the base fields for the object that should just be used in absolutely every query done by this class
public List<Schema.SObjectField> getSObjectFieldList(){
return new List<Schema.SObjectField>{
Contact.Id,
Contact.Name,
Contact.FirstName,
Contact.LastName
};
}
//Allows you to easily get the object type for the object being queried by this class
public Schema.SObjectType getSObjectType(){
return Contact.SObjectType;
}
//Allows you to create a query that selects records by a set of ids (basically adds the WHERE Id IN :ContactIds to the query)
public List<Contact> selectById(Set<Id> contactIds){
return (List<Contact>) selectSObjectsById(contactIds);
}
}
When you create a Selector class that extends the fflib_SObjectSelector class you have the option to send some parameters to its constructor that determine how to the selector class functions. They are the following (in order of parameters passed to the constructor):
- Would you like to allow your class to use field sets when building the initial query fields for your selector layer class? By default this parameter is set to false.
- Would you like to enforce CRUD (Object level create, read, update, delete) security on your selector layer class? By default this parameter is set to true.
- Would you like to enforce FLS (Field level security) on your selector layer class? By default this parameter is set to false.
- Would you like your selected fields in your query to be sorted alphabetically when your query is created (this is literally just a sort call on a list of strings in the code)? By default this parameter is set to true.
If you would like to alter any of these settings for your selector class you can do the following:
public inherited sharing class Contact_Selector extends fflib_SObjectSelector
{
//In our selector classes constructor we are calling the fflib_SObjectSelector using the super() call
//and setting out parameters.
public Contact_Selector(){
//This is completely optional. If you like the defaults listed above you do not have to call the super class constructor at all.
super(false, true, true, false);
}
}
Note that this is completely optional, if you like the default behavior listed above, just don't bother calling the super method and overriding them!
One of the biggest benefits of the selector layer is selected field consistency in your queries. If 99% of the time you are querying for the subject field on your Case object, why not just query for it by default without ever thinking about it again right?? Well the getSObjectFieldList method that you implement in your Selector classes does just that. Here's how to implement that method in your selector:
public List<Schema.SObjectField> getSObjectFieldList(){
//Note that this is using concrete references to the fields, not dynamic soql (here at least). This is to ensure the system knows
//your code is dependent on these fields so you don't accidentally delete them some day.
return new List<Schema.SObjectField>{
//In this list, place every field you would like to be queried for by default when creating a query
//with your selector class.
Contact.Id,
Contact.Name,
Contact.FirstName,
Contact.LastName
};
}
If you choose to enable field sets to allow for default field selection for your selector class, you can implement the following method to select fields from the field set to be included in your queries:
public override List<Schema.FieldSet> getSObjectFieldSetList(){
return new List<Schema.FieldSet>{SObjectType.Case.FieldSets.CaseFieldSetForSelector};
}
The major benefit of using the field sets for query fields is you can add new fields on the fly without adding extra code. This becomes super important if you're building a managed package.
By default all Selector Layer Classes that extend the fflib_SObjectSelctor are ordered by the Name field (if the name field isn't available on the queried object it defaults to CreatedDate). If that's kewl with you, no need to override it, but if you'd prefer the default sort order for your select class be different then you just need to override the following method like so:
public override String getOrderBy(){
return 'Subject';
}
If you wanted to order by multiple fields you would just do the following (basically just create a comma separated list in the form of a string):
public override String getOrderBy(){
return 'Subject, Name, CustomField__c, CustomLookup__r.Name';
}
While there are many other methods within the fflib_SObjectSelector class below are the methods most commonly utilized in implementations.
Part 15: The Difference Between Unit Tests and Integration Tests