Is it possible to get a Custom Setting without the cost of a SOQL query and at the same time do it DYNAMICALLY without hardcoding the setting?

Once I had the illusion that accessing custom setting is always free and does not consume any governor limits. Until today: I’ve learned the hard way that this is only half-true.

It is true, that this comes without the cost of a query:

MyCustomSetting__c.getall().values();

But this DOES cost you a query

database.query('select Id from MyCustomSetting__c ');

Now how can I get the setting dynamically in a way that my code runs on every org regardless of the existence of MyCustomSetting__c? I need to hide the setting from Salesforce so that I can use something inside of a try/catch. If the setting does exist I need to get some values. If it does not exist I fall back on default values.

Additionally I need a way to update records of the settings synchronously in trigger contexts.

Questions

  • Can this be done free of charge of any query limit?
  • Where is the documentation that using database.query() for CustomSetting cost limits? I can not find it. If there is no documentation, I would assume that either the documentation is wrong or incomplete OR the limit consumption is a BUG.

Update 2021-11-24

I’ve tried to use CustomMetadataType instead. It failed.

CustomMetadataType (CMT) is similar to CustomSetting (CS) and CMT looked very promising at the first glance. I watched this video from 2019 where CMT is advertised as more powerful successor of CS. Especially this slide convinced me to give them a shot:

enter image description here

BUT in fact CMT is unusable for me, because it does not support DML to update records. Records can be updated asynchronously with APEX. Not sure if this works in trigger context, but the possible timing issues are not acceptable for my requirements. I need updates of records in sync.

So I would not agree that CMT is on par with CS in all aspects. DML and in sync updates are crucial for some scenarios.

Answer

There’s no way to do this directly; there’s no unique common parent type or interface, we can’t access namespace properties dynamically, we don’t have proper language reflection, etc. Basically, the type system in Apex isn’t robust enough to allow us to do this.

The closest you can get to would be to introduce an interface and wrapper classes.

interface iCustomSetting {
  public Map<Id, sObject> getAll();
}
public class MyCustomSetting implements iCustomSetting {
  public Map<Id, sObject> getAll() {
    return MyCustomSetting__c.getAll();
  }
}

Which you then use dynamically:

public static Map<Id, sObject> getAllForCustomSetting(String settingName) {
  iCustomSetting setting = (iCustomSetting)(Type.forName(settingName).newInstance());
  return setting.getAll();
}

You still have to write a new class for each custom setting, but now you can dynamically select from any of those custom settings by name.

It would be nice if we had some way to do this directly, but that just doesn’t exist in Apex. If you really want to save those SOQL limits, and want dynamic access, you have to build it yourself.

As a side effect, you still have a hard-coded reference to the setting, so it must exist in the org. You could, I suppose, package additional extension packages so that the setting and the interface implementation are in can be installed separately, with the interface in the core package.

Attribution
Source : Link , Question Author : Uwe Heim , Answer Author : sfdcfox

Leave a Comment