23

I have an app which is fired from a trigger on FeedItem and FeedComment. I can easily grab the posting user, date, parentid and type. However I am finding it difficult to rapidly determine the object name associated with that parent ID.

Ideally this would be written as a method within a class which would be called and return 2 things, the object Name and one of the key identifying fields from the object, like:

  • Object: Account, Record: ABC Company, Inc.
  • Object: Case, Record: Case # 1234
  • Object: Group, Record: Group Name
  • Object: User, Record: Mike Smith

Thoughts?

  • Note: please be sure to read Andrew Fawcett's answer (fairly recent and low scoring) as a much more efficient way to solve this problem. Hopefully Texas Rob will mark it as the accepted answer. – tomlogic Aug 30 '13 at 23:34
13

When treated as a String, the first three characters of ParentId represent the object prefix, which can be used to search for the object in the getGlobalDescribe map.

for example.

// This will be set to the object description metadata if found
Schema.DescribeSObjectResult object_desc = null;

// Get the Id we're searching for
String parent_id = feed_item.ParentId;

// Search every object in the getGlobalDescribe() map to check key prefixes
for( Schema.SObjectType t : Schema.getGlobalDescribe().values() ){
    Schema.DescribeSObjectResult desc = t.getDescribe();

    // If the Id starts with this objects prefix, then we know the type
    if( parent_id.startsWith( desc.getKeyPrefix() )){
        object_desc = desc;
        return;
    }
}

if( object_desc != null ){
    System.debug('Object type is: ' + object_desc.getName() );
    SObject record = Database.query( 'SELECT Name FROM ' + object_desc.getLocalName() + ' WHERE Id = :parent_id" );

    System.debug('Object name is: ' + record.get('Name'));
}

If you wanted to return a different field for each object, you'd have to check the object type before building the query, include the relevant field, and then return that.

i.e.

if( object_desc.getLocalName() == 'Contact' ){
    String name = [SELECT LastName FROM Contact WHERE Id = :parent_id].LastName;
}
  • 2
    Re: fast. This approach isn't parcticularly speedy as there's a lot of SOQL query round trips. There's currently a pilot for new SOQL syntax that works on polymorphic relationships. More details should be in the release notes for winter 13. This should make it possible to resolve all names via a single query and net some major performance improvements. – ca_peterson Aug 15 '12 at 19:36
11

You can obtain the object type from an Id directly using the Id.getSObjectType method (which I don't think was around the first time this question was answered btw). Without having to describe all objects and filter by the key prefix (which is also still technically a correct answer though is less direct now).

Returns the token for the sObject corresponding to this ID. This method is primarily used with describe information.

This is an example from the docs here.

    // Get the sObject token from the first ID
    // (the List contains IDs of sObjects of the same type).
    Schema.SObjectType token = objIds[0].getSObjectType();

    // Using the token, do a describe 
    // and construct a query dynamically. 
    Schema.DescribeSObjectResult dr = token.getDescribe();
    String queryString = 'SELECT ownerId FROM ' + dr.getName() + 
        ' WHERE ';
    for(ID objId : objIds) {
        queryString += 'Id=\'' + objId + '\' OR ';
    }    
    // Remove the last ' OR'
    queryString = queryString.subString(0, queryString.length() - 4);
  • I think you could build that dynamic SOQL queryString to end in 'WHERE Id IN :objIds', and avoid manually iterating through them. – tomlogic Aug 30 '13 at 23:20
  • Good point! It was copied from the docs, tut tut on them and me for not improving it before posting! ;-) – Andrew Fawcett Aug 30 '13 at 23:22
3

I think James answered well to the answer, however I've blogged which answer the same. Please take a look over it and let me know if you face any problem.

http://forceguru.blogspot.in/2011/12/fetching-sobject-type-from-record-id.html

2

The Salesforce sObject record Ids always start with the same 3 characters (prefix) for a particular type of object. For standard objects, this is the same across all orgs and for custom objects this is true only within the org it is defined in (the same prefix might hold good for another object in another org)

With that, you could determine what object your parent is using something like:

global class ObjectHelper {
    public static String whichObject(String parentId) {
        String keyPrefix = parentId.substring(0, 3);

        if(keyPrefix == '001')
            return 'Account';
        else if(keyPrefix == '003')
            return 'Contact';
        //...
    }
}

If you want to do this more dynamically you could use the keyPrefix property from the DescribeSObjectResult() call

You could invent more if you want more information than just the Object name

1

Make sure to use the approach above as describe by James. DO NOT hardcode the prefix values, use the describe methods. Prefixes are not constant across Salesforce Orgs for custom objects. So if you have Sandbox and Production the prefix for "CustomObject__c" will not always be the same.

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.