5

I am getting this error as i have used getdescribe under for loop.Can some tell me how should i solve this..how to create map for this .please help. Thanks

           Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe();               
           List<SObjectType> objectsUSE=new List<SObjectType>();

            for (Schema.SObjectType ot : gd.values())
            {
                **Schema.DescribeSObjectResult ds = ot.getDescribe();**  
                if(!ot.getDescribe().isCreateable())
                  continue;   
                if(ds.getRecordTypeInfos().size() > 0)
                objectsUSE.add(ot);

            }
  • How are you getting 'gd' ? You could attempt to remove the duplicated (if any) sSObjectTypes, but if even that may reach above 100 I think you may need to think of asynchronous processing. – Samuel De Rycke Sep 18 '13 at 9:27
  • Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe(); – miku Sep 18 '13 at 9:42
  • i dont know how to solve this mate..can you give me some eg.. – miku Sep 18 '13 at 9:56
6

The exception is coming from the getRecordTypeInfos() call, not the getDescribe() call. The describe governor limit only applies to a small number of describe calls listed in the governor limit documentation. The two that people typically run into are fields and getPicklistValues. This one was new to me.

You appear to want to build a collection of sObject describes, but only if they have record type enabled (and are currently accessible by the running user). I suspect you are going to have to come up with a different way of determining this, or filter out more objects before you make the getRecordTypeInfos call in the first place.

If you want to find out all sObjects that support record type in the first place, the RecordType object has an sObjectType field that is of type picklist. You could determine the sObjects that support record type at all by making a describe call for the picklist values of that field as follows:

Set<String> sObjectsThatCanHaveRecordType = new Set<String>();
Schema.DescribeFieldResult field = RecordType.sObjectType.getDescribe();
List<Schema.PicklistEntry> entries = field.getPicklistValues();
for (Schema.PicklistEntry entry : entries){
  sObjectsThatCanHaveRecordType.add(entry.getValue());
}

Then, in your code above, instead of calling getRecordTypeInfos, check that the current sObjectType is in the set:

if(sObjectsThatCanHaveRecordType.contains(ds.getLocalName()))
            objectsUSE.add(ot);

Note: I'm not certain whether you would use getName or getLocalName here. I don't know if the RecordType.sObjectType field stores the qualified sObject name where namespaced sObjects are used, or the unqualified name as I currently don't have an org with a namespaced package installed.

But this is imperfect as any object that supports record type could be used. So maybe a better approach would be to use a query for the sObjectType field of the RecordType object. Create a set collection containing all active record type sObjectType field values. Then use the same logic that I used above and determine whether or not you have a record type enabled object from the set. I did it this way.

Set<String> rtObjNames = new Set<String>();

for (RecordType rt : [select sObjectType from RecordType where IsActive = true]) {
    rtObjNames.add(rt.sObjectType);
}

System.debug(rtObjNames);

    Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe();               
    List<SObjectType> objectsUSE=new List<SObjectType>();

      for (String objName : rtObjNames)
      {
          Schema.SObjectType ot = gd.get(objName); 
          if(ot.getDescribe().isCreateable())
            objectsUSE.add(ot);   

      }

System.debug(objectsUSE); 

Of course, this has downsides as well. First of all, you burn a query. Bummer that, but not the end of the world. Second, in a very large organization that heavily leverages record types, you could eat into the 50k query rows governor limit (let's say 50 object, 10 record types, that's 500 rows = 1% of my total limit)...so I'd be sure to manage this if your code is using other queries elsewhere.

In the end, I think this last option is going to give you the best chance of success.

EDIT: I had a rethink of how I initially solved this and it occurred to me that once I had queried the record types in use from RecordType, I should just use the global describe map, so I refactored the for loop to go over set of strings instead of the entire list of sobject types in the global describe map. Duh! Much better.

3

I use for example the following approach to map all picklist values and labels from the sObject field:

public transient Schema.DescribeFieldResult result = Object__c.Picklist__c.getDescribe();
public transient List<Schema.PicklistEntry> entries = result.getPicklistValues();
public Map<String, String> mapValues = new Map<String, String>();

public MyConstructor(){    
    for(Schema.PicklistEntry e: entries){   
        mapValues(e.getValue(),e.getLabel());
    }
}

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.