fflib-apex-common icon indicating copy to clipboard operation
fflib-apex-common copied to clipboard

How to Use FieldSets with Application.Selector.newInstance?

Open Daniel-Dragon opened this issue 4 years ago • 6 comments

Hello, I have more of a discussion question regarding how to enable FieldSets to be more flexible.

  • If you're using Application.Selector.newInstance how do you provide the parameter for adding the fieldsets?
  • Is there a point to having multiple FieldSets? Or do most people just created like a "Default" fieldset that has extended fields to query for?

Daniel-Dragon avatar Jun 02 '20 15:06 Daniel-Dragon

I'm not entirely sure I understand your first bullet point -- Can you provide an example of that usage? The most common usage of fflib_SObjectSelector is to subclass it for your own object and define the list of field sets you want to query by overriding the virtual getSObjectFieldSetList()

The purpose for having multiple Field Sets usually becomes evident if you need multiple Selectors -- i.e. a 'get me the kitchen sink' Selector that enumerates all fields and perhaps a more narrow Selector where heap size or some other consideration (FLS) makes it convoluted to use a single kitchen sink Selector.

daveespo avatar Jun 03 '20 17:06 daveespo

Please keep in mind that this could be a serious misunderstanding on my part. I'm slowly piecing together how this is supposed to work and reading the book! So my assumption is that whenever we need the Selector "injected" anywhere we want to use Application.Selector.newInstance, this will allow us to inject a mock when testing, and allow us to swap out implementations if they change.

So with that assumption, what I am saying is If I'm using the Application static class to get the selector right? Say Account object so I have an AccountsSelector class, and it's registered in my Application class.

So now I'm supposed to use Application.Selector.newInstance(Account.SObjectType) when I want to inject it? (If that part is wrong then my whole question is wrong) What if I want to inject the "Kitchen Sink" this time?

Daniel-Dragon avatar Jun 04 '20 20:06 Daniel-Dragon

All of that is right on, and as long as the "Kitchen Sink" implements fflib_ISObjectSelector, you'll be fine.

Additionally the selector implementation could contain a static newInstance() method that calls Application for you, so the usage might look like: List<KitchenSink__c> sinkList = KitchenSinkSelector.newInstance().selectSinksByVolume(...); See the sample usage project, where the AccountsSelector [1] has it.

Welcome to AEP, and I look forward to hearing about your experiences and perhaps some suggestions.

[1] https://github.com/apex-enterprise-patterns/fflib-apex-common-samplecode/blob/master/sfdx-source/apex-common-samplecode/main/classes/selectors/AccountsSelector.cls

stohn777 avatar Jun 05 '20 04:06 stohn777

Ah this is perfect thank you! I knew I saw this somewhere. OK, so that leaves the last point of question still open I think which is the FieldSet itself.

So I pulled the example here from Andrew Fawcett's book. The snippet below is extending fflib_SObjectSelector and is intended to be extended further with an actual selector class to give context.

public abstract class ApplicationSelector extends fflib_SObjectSelector {
  public ApplicationSelector() {
    this(false);
  }
   public ApplicationSelector(Boolean includeFieldSetFields) {
     // Disable the default base class read security checking
     // in preference to explicit checking elsewhere
     this(includeFieldSetFields, false, false);
   }
   public ApplicationSelector(
     Boolean includeFieldSetFields,
     Boolean enforceCRUD, 
     Boolean enforceFLS) {
     // Disable sorting of selected fields to aid debugging
     // (performance optimisation)
     super(includeFieldSetFields, enforceCRUD, enforceFLS, false);
 }
}

These constructors seem to give us the flexibility to includeFieldSetFields, enforceCRUD, enforceFLS, ETC Right? How can we leverage these constructors (To get the kitchen sink implementation by saying includeFieldSetField = true) when using an implementation of the class though, how can I call one of these constructors? Without explicitly defining the class that I'm creating of course! Because if I do that then I lose the ability to Mock.

Daniel-Dragon avatar Jun 05 '20 23:06 Daniel-Dragon

G'day @Dan-Baba

"These constructors seem to give us the flexibility to includeFieldSetFields, enforceCRUD, enforceFLS, ETC Right? "

  • Yes, that is correct

"How can we leverage these constructors (To get the kitchen sink implementation by saying includeFieldSetField = true) when using an implementation of the class though how can I call one of these constructors? Without explicitly defining the class that I'm creating of course! Because if I do that then I lose the ability to Mock."

  • So first of all, if you have not already review the sample code, take a look at the Application.cls starting at line 52. This is a typical example of the Application class setup in a non-DX environment. The AT4DX version of the Application.cls starting at line 40 is what you would use if you have a DX project with multiple second generation packages.
  • In both cases, the methods are not exposed to activate the extra features. Having said that, the AT4DX version is based on the ApplicationSObjectSelector which is itself based on the fflib_SObjectSelector. The ApplicationSObjectSelector does enable field sets as it is part of the AT4DX fieldset injection functionality, so that might help you.
  • In both cases, the Application classes have a series of setMock methods to help you take advantage of that functionality. Look in the fflib-apex-common-samplecode and the at4dx-samplecode projects for examples of its usage.

Trust this helps.

ImJohnMDaniel avatar Jun 06 '20 17:06 ImJohnMDaniel