1

I need to check that the Record Type of the record whose change caused my trigger to fire is listed in a Custom Setting WEID__c.

Until now I have been been using

trigger WE_MRFv2 on Opportunity (after insert, after update) {

    List<WEID__c> weids = WEID__c.getall().values();
    Set<Id> validRecordTypeIds = new Set<Id>();

    // add Opportunity Record Type Ids from Custom Setting to list of valid Ids      
    for(WEID__c weid : weids) {
        try {
            validRecordTypeIds.add(weid.WEOppId__c);
        } catch (System.StringException e) {
            System.debug(
                System.LoggingLevel.ERROR,
                'Invalid Record Type Id ' + weid.WEOppId__c);
        }
    }

If(Trigger.isInsert){
        for(Opportunity o : Trigger.New){
            if(validRecordTypeIds.contains(o.RecordTypeId))
            {
            //do something
            }
        }
    }

But it's been suggested that I change this to

trigger WE_MRFv2 on Opportunity (after insert, after update) {

    WEID__c weid = WEID__C.getAll().values();

    If(Trigger.isInsert){
        for(Opportunity o : Trigger.New){
            if(weid.get(o.RecordType.Name) != null)
            {
            //do something
            }
        }
    }

As the Record Type name is more stable (when copying code between Sandboxes & Production) and I can then avoid hard coding Record Type Ids when creating / referencing Custom Settings in my Test Classes.

UPDATE --

In the end the below portion of my question was irrelevant since even if I could fetch the Record Type Name from the Custom Setting, I can't check that against the Opportunity Record Type Name.

--

The only problem is that I have several fields in the Custom Setting containing the same value and I'd like to avoid having to create a new Custom Setting each time I need a new list of Record Types (which are currently just stored in a new field for the same Custom Setting).

So I see the following error

System.QueryException: List has more than 1 row for assignment to SObject

Supposedly at line WEID__c weid = WEID__C.getAll().values();. But I'm guessing that the issue actually occurs when I try to fetch the values from weid at line if(weid.get(o.RecordTypeId) != null)?

The 'cost' of fetching the values from the Custom Setting using an SOQL query outweighs the benefit of switching to using Record Type Names, from my point of view.

Is there alternative way to fetch the Custom Setting values which I need (contained in field WEOppId__c), to query later in the Trigger?

  • whats wrong with the first trigger ? The error "List has more than 1 row for assignment to SObject" is at the line "WEID__c weid = WEID__C.getAll().values();" as you have said. – Ajay Dubedi Jul 3 '15 at 10:10
  • It works but it's fetching the Record Type Id rather than the Name, which I want to use instead. – Alex S Jul 3 '15 at 10:12
  • WEOppId__c field contains the id or name of the recordtype ? – Ajay Dubedi Jul 3 '15 at 10:16
  • Id now but will contain the Name if I can switch - so obviously I'd expect the line if(weid.get(o.RecordTypeId) != null) not to find any results. – Alex S Jul 3 '15 at 10:16
  • I guess you can use 2 fields , 1 for id, and 1 for name. and use a map in trigger. – Ajay Dubedi Jul 3 '15 at 10:19
2

A problem with switching to the name is that in triggers only the immediate fields of objects are available. So RecordTypeId is available but the related field that has the record type name RecordType.Name is not without performing an extra query.

ID values in sandboxes are the same as in production because a sandbox is a clone of production.

So I suggest that you do not make this change.

|improve this answer|||||
  • Just a quick follow up on this, if I created a formula field on the object to display the RecordType.DeveloperName and referenced that instead of the Id in my code, would I potentially encounter any limitations? i.e. would I not be able to access the formula field value in certain scenarios, when I would have been able to reference the Id? – Alex S Jul 20 '15 at 15:33
  • 1
    I know it's tenuous but as far as I'm aware, the Ids of Record Types which are first created in the Sandbox won't match the Record Type Id when it's deployed in Production, until the Sandbox is refreshed.. – Alex S Jul 20 '15 at 15:40
  • 1
    @AlexS There may be limitations limitations but I don't know what they would be. Would allow triggers to use the developer name without any more querying though. – Keith C Jul 20 '15 at 15:43
  • If I could hassle you once more for this question, I'd be interested to hear your thoughts on binaryLady's new answer on this post! – Alex S Jul 28 '15 at 12:56
  • @AlexS I think binaryLady's code seems to be about allowing a sub-set of the record type IDs to be identified by name. That doesn't look immediately related to your question where you seemed to have the ID values already in a custom setting. – Keith C Jul 28 '15 at 13:25
1

you can use a map like this:

Map <Id, String> mymap = new Map <Id, String> ();

for(WEID__c weid : weids)
{
    mymap.put(weid.idfield, weid.WEOppId__c);
}
|improve this answer|||||
  • Please see Keith's answer, I don't think that this would work for me because I can't retrieve the value from the Custom Setting based on the Opportunity's Record Type Name.. – Alex S Jul 3 '15 at 10:40
  • you can fetch record name from custom setting based on opportunity's record type id – Ajay Dubedi Jul 3 '15 at 10:52
  • That's the problem though, if I'm using the Opportunity Record Type Id to fetch the value then I might as well stick with the first version of the code from my question, unless I'm missing something? – Alex S Jul 3 '15 at 11:26
1

To Keith's answer, if you use a list to store the values from your custom setting and then iterate through the values returned from your describe call you will be able to only execute the trigger when the record is a match like this although you will add the part for the custom setting: No queries required! yay :)

//use the describe class to get Opportunity record type info
Map<String, Schema.RecordTypeInfo> RT = Opportunity.SObjectType.getDescribe().getRecordTypeInfosByName(); 

//List of record types to look for, note the label is used not the api name
List<String> recordTnames = new List<String>{'record type label','another record type label', 'etc'}; 

//List to store ids to run the trigger against
List<Id> idsToCheck = new List<Id>();

for(String check : recordTnames){
    //only works if the record type in the list exists 
    if(RT.containsKey(check)){
        SYSTEM.debug(RT.get(check).getRecordTypeId());
        //add the record type ids to the list for your trigger logic
        idsToCheck.add(RT.get(check).getRecordTypeId());
    }

} SYSTEM.debug('ids ' + idsToCheck);
|improve this answer|||||
  • 1
    To @keithC and AlexS, if you are trying to avoid hard coded ids anywhere which will not be consistent across all orgs than you can use the record type label. You can pull all of the attributes of the record type on any object without any queries or hitting any limits (as describe limits have been removed) this way. If you still wish to use a custom setting, those labels may be stored there. Though that seems redundant as the custom setting is a key-value pair which you don't really need if you only need the label to execute the describe. – binaryLady Jul 28 '15 at 14:37
  • 1
    I think this should be marked as the correct answer. The one above is just wrong, as Ids are not reliably identical througout the systems. This one's quick, readable and clean. We use a little helper class, that you just pass the SObjectType to and it gives you a map<String, Id> mapping Labels to RecTypeId. Currently switching to using custom Labes in case the name of a Record Type changes (happens a lot unfortunately). – Schnaps Nov 28 '19 at 8:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.