Preface: this post is part of the Advanced Apex Concepts series.
Custom Settings are a hidden gem in Apex that always impresses people, especially bosses!
Custom Settings are variables that you use in your code but set and modify outside of your code.
Here’s an example:
You’re writing a trigger that sets a “Customer Service Rep” field on an Account every time there’s a high value Opportunity associated with it. Two things are certain: (1) The CSR on duty changes every week and (2) the threshold for a “high value” opp changes often since your company is expanding.
A perfect use case to use Custom Settings to set the CSR on duty and the “high value” opp threshold!
Benefits of using Custom Settings:
Step 1: Create a Custom Setting “object” for your trigger:
Setup >> Develop >> Custom Settings >> New
Step 2: In your Custom Setting object, create Custom Fields for each needed variable:
Step 3: Create a Custom Setting record and edit its variables
Navigate to your Custom Setting >> Manage >> New
Step 4: Use your Custom Setting in your code!
trigger AddCSR on Opportunity (before insert) {// Grab your Custom Setting values CSR_Settings__c settings = CSR_Settings__c.getInstance('csr'); String CSR_USER_ID = settings.CSR_User_ID__c; Decimal OPP_MIN_VALUE = settings.Opp_Minimum_Value__c;// Create a master list of accounts to bulk update List<Account> accounts = new List<Account>(); for (Opportunity opp : Trigger.new) { // Make sure we meet the minimum thresholdif (opp.Amount >= OPP_MIN_VALUE) {// This is a trick to get the related account! Account acc = new Account(); acc.Id = opp.AccountId; // Update the CSR and add to master listacc.CSR__c = CSR_USER_ID;accounts.add(acc); } } // Update the master list of accounts update accounts; }
Now if you need to edit the CSR on duty or the minimum Opportunity amount threshold, simply edit the record in Step 3 – no rewriting or deploying code necessary!
One important note – custom Settings aren’t automatically transferred between sandboxes and production, so make sure you include them in both places or your code will break!
Next post: How to simplify the most complex triggers!
In this trigger i think event should be After insert because we are trying to
perrform Dml operation on Other object i.e Account.
in this you are using before insert but in before event the value of system field
is null(i.e id,lastModifiedBy etc)
I dont understand why before insert and update dml operation.
Thanks& Regards
Ganesh Gavhane
Can someone please tell how to create a custom field , which is required in this topic. Because if its going to be a look up field on account object, then what will be the parent object.
Sorry not custom field, I mean Lookup field on account object
Can please someone tell, how to create lookup field in this chapter.
There’s no look up field option in custom settings and if it gonna be a lookup on account object , then with whom.
Create a Hierarchical custom setting “TriggerSetting“. Create fields for all triggers developed in your system. This custom setting should be used to enable/disable any trigger from your org.
Create a Hierarchical custom setting “TriggerSetting“. Create fields for all triggers developed
in your system.This custom setting should be used to enable/disable any trigger from your
org.
Hi David,
I want to replace the custom object with custom setting.
But the object is being queried with Order By on different fields in different classes.
Could you please help me in this.
select id,name from obj1 where *** order by field1
select id,name…. from obj1 where ** order by field2.
And all the fields are getting used in the code.
Regards,
Priyanka Nimkar
how do u create account without enter the required field account name in u r code……..
The account already exists =)
hi david …u used update DML ….but i think it should be insert there
All accounts already exist!
Hi David– I have a trigger that automates chatter notifications on a record based on field changes. I’m planing to use custom settings to determine the notification text so that my customer can make changes to the notification once I leave. Right now I’m able to include field values in the notification text in my trigger (ie: Account.Name + ‘ was just updated to ‘ + Account.Status__c). Is that possible using custom settings? I know I can default the text but how would I reference fields on the record since there is no formula field option in custom settings.
PS–I feel like we might become best friends as I’m learning to code, hope that’s okay with you! :)
Hi All,
Kindly let me know is there any way to modify the custom seetings values in visualforce page. please share the code .
Thanks in Advance,
Kumar
It’s possible! Don’t have the code but you can do it! Or just link to the actual custom setting page.
Hey David,
I am in such a situation that I need to update record in After Trigger. Is it possible.??
My scenario is that I want to fire a trigger only once even for multiple transactions after meeting my conditions.
Totally possible, need to use static variables. Good luck!
David, am i right, settings ‘type’ uses singleton pattern?
Hi David,
Have got a question in the above custom settings trigger.
// This is a trick to get the related account!
Account acc = new Account();
acc.Id = opp.AccountId;
In the above code, we are creating a new account. and the current Oppty’s Account Id is passing to the new account. so would it be a duplicate?.. I didn’t get the the exact intention of the code. Pls help me. Thanks a lot for your time .
Not really actually!
We’re not creating a new Account, we’re creating a new reference to the same account using the opp’s ID. The alternative would be to query the account outright, but that would take one of our SOQL queries.
Hope this makes sense!
David
Hello David,
I have got clear.. :) Thanks :)
Good Article. I have a Apex Scheduled job that needs to cleanup some data every now and then. I started using CSRs to record my previous data points like last_sync_dates here so that my Apex code can start looking from that point.
Hi david, I don’t understand why we should take lookUp filed on Account, I am taking text field CSR__c on Account. Trigger is working fine with insert and update opportunity. and most important thing is , if we tried to take lookup field on Account , which object we should select for “Related to”. Custom setting object is not appearing in list.
Swapnil
thnks
hey david,
where do we get this CSR user id from ?? like in the snapshot u hav put CSR user id …..
if CSR ID is related to a particular account Id for whose opportunity we want to check …
like i tried puting CSR id (in custom settings) that of a particular account id(which i created new)
next when i create an opportunity for that particular account .
on save i gt this error.
Error: Invalid Data.
Review all error messages below to correct your data.
Apex trigger AddCSR caused an unexpected exception, contact your administrator: AddCSR: execution of BeforeInsert caused by: System.NullPointerException: Attempt to de-reference a null object: Trigger.AddCSR: line 4, column 1
Make sure the name of the custom setting is “csr”
The URL of any User record =)
Hi David, in the example above, i could not understand one thing : that Trigger is written on before insert and within the code its doing a update account… wouldn’t this DML statement be always relevant to the trigger event .???
hahahaha you’re right, I didn’t think anyone would notice that! I used insert only to make the code simpler
I understood that the trigger fires everytime an Opportunity is inserted, but actually updates accounts. Therefore you have to write a DML statement since you are “acting” over a different object that the triggered-object.
And it is update instead of insert since all accounts have to be created prior to opportunities.
Hi David,
Im getting “Invalid field CSR__c” . I pretty much copied/paste same code above. Not sure where to look to correct..
Gotta create that lookup field on the Account first! Sorry I didn’t make that clear!
What Account? Is this a custom account that we created earlier? As far as I know we can’t create a lookup field on the Account object? Thanks :)
ps Nice SpiderMonster suit!!
David, regarding creating the custom field “CSR__c” on the accounts object, did you literally mean it should be a LookUp type? Shouldn’t it be a type of Text(18) (Unique Case Sensitive)? Thx.
Gotta be a lookup type! Even though it’s a lookup, it’s populated by an ID.
Thank you for this David. Your humor is clever and really does help to keep people engaged! I am still working my way through but Chapter 6 is absolutely my favorite so far! :)
hehehe someone thinks I’m funny!!! ^_^_^_^_^
Note to self (and anyone else this might help):
* Make sure that your Custom Setting visibility is set to “Public”
* The record name is case-sensative. Bye != bye
Thank you Virginia!! You are right on!!
I’ve been trying to write a test class for this trigger and I think I’m almost there but I can’t seem to figure out how to get the id of the account I created in the test class to then assign it to the Opportunity I’m creating as well.
Here is the section of the test class I’m struggling with. Earlier in the test class I created a test account. Here you can see I’m searching for it and using it to do an assertion. I’m also trying to reuse that id to create a new opportunity related to that Account but I keep getting the error “Error: Compile Error: Illegal assignment from Id to SOBJECT:Account at line 41 column 9”. I’m guessing there is a proper way to create a record and get that right back? If so whats the best way to use that when you create a new record?
Thanks so much and your site/tutorials are AMAZING! Keep up the great work!
List accountAssert = [SELECT Name, Id, CSR__c FROM Account
WHERE Name = ‘Test Account’
LIMIT 1];
System.assertEquals(users[0].Id, accountAssert[0].CSR__c);
Opportunity o = new Opportunity();
o.Name = ‘Test’;
o.Account = accountAssert[0].Id;
o.Amount = 10.00;
o.CloseDate = ’01/01/2099′;
o.Stage = ‘Prospecting’;
hehehe all you need to do is change that line to:
o.AccountId = accountAssert[0].Id;
Then give yourself a pat on the back for getting even that far on your own!
P.S. you can find a full list of valid fields of Opps here:
http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_objects_opportunity.htm
David
Hi David, i have written a test class for this but i am getting only 18% coverage.
Unable to understand where am I going wrong, could you pl have a look at the below code and suggest [Also, post testing coverage,some lines are blue and some red or sometimes its purple and pink on the trigger written.. : what does they mean?)
@isTest
public class TestClassAddCSR {
static testmethod void NewOppWithMinAmount()
{
Opportunity op = new Opportunity();
op.Name =’test ADDCSR’;
op.closeDate = date.today() + 30;
op.stagename = ‘Prospecting’;
op.AccountId = ‘001i000000kHASP’;
op.Amount = 600;
insert op;
}
}
Feeling goood David, i could fix the above test class and now got the 100% coverage. :D…but now unable to understand how test class data exactly works in salesforce.
I am not able to understand is, when i write insert DML statement in test class, why it is not creating a new opportunity in the application. As i was expecting after running the test class i would see a new opportunity “test ADDCSR’ in the application, but i dont ???
Great question – anything created during your test class simply exists during the test. After the test is done it’s all deleted =)
Thanks David. I am waiting for more series from you : On Integration and Dynamic APex/Visuaforce.
Cant wait to learn more… Cheers!!
Since custom settings are cached, if you update the value of an existing one is there a way to refresh the cache?
Salesforce will automatically do this for you =) No need to worry about Custom Setting updates not reflecting!
This is one of the Best chapters that i have come in the Site. I have been reading the chapters from the very first and i just cannot leave it. Really a great explanation of the things in apex . I remember reading the Force.com fundamentals and dozing off countless times, but David you add a whole new dimension , a great spark to Apex learning. keep up the good work!!!!
Sourav, I am so glad you feel this way about my site!! It is an honor!!!
David,
Can I update the costom settings variables’ value using any trigger or workflow? The reason I’m asking this is because sometimes any Org wants to dynamically change the values based on some conditions and they don’t want to depend on manual intervention (Admin) to do so. If you can share some inputs on this, would be very helpful..!!
Hey Ayan,
You definitely can!
Let’s say your custom setting is called “My_Settings__c”.
Your settings record is called “default”
And you have a field on it called “Number__c”
You’d be able to update it simply like this:
My_Settings__c settings = My_Settings__c.getInstance(‘default’);
settings.Number__c = 2;
update settings;
Note that these scenarios should be rare – sometimes it’s better in these cases to create a custom object!
David
Just pointing out that custom settings are really custom objects and their records stored like any other custom object. The difference is they are cached so their records can be accessed quickly via the getInstance() method. That is, for a custom object that is not a custom setting, the getInstance() method is the same as executing a SOQL query by Name (WHERE Name = :parm). Because custom settings are custom objects that are cached, there are limits on how much data can be stored in each record and in the custom setting cache in total (10Mb in API v29). Otherwise all interactions such as queries, loading records, and record sharing that apply to all custom objects also apply to custom settings. Indeed, the meta component xml for a custom object vs custom setting is identical except the custom setting will include the additional elements:
List
Public
Sorry, those elements got escaped out:
[customSettingsType>List[/customSettingsType]
[customSettingsVisibility>Public[/customSettingsVisibility]
Totally right! Thank you Paul!
That is the perfect answer to #10 on the Chapter 6 quiz!
https://www.sfdc99.com/2014/03/17/quiz-chapter-6/
David, any specific recommendations/considerations for handling custom settings in Test Code?
This goes in the hall of fame as one of the best questions asked on this site!
If you’re relatively new to Apex, consider yourself an awesome student with lots of promise =)
The correct way to test this is to create your Custom Setting record in your test class, ie:
CSR_Settings__c settings = new CSR_Settings__c();
settings.Name = ‘csr’;
settings.CSR_User_ID__c = // Some user ID
settings.Opp_Minimum_Value__c = 5000;
insert settings;
Salesforce treats Custom Settings very similarly to a custom object, the biggest difference is that you don’t need to do a SOQL query to get this information into your trigger, which is very convenient!
Keep on learning how to code, you are making good progress.
David
Thanks for the quick response, David. Appreciate it!