Die Magie der Salesforce ID

Zu jedem Salesforce-Blog gehört ein Beitrag zur Salesforce Id. Im Übrigen der erste Beitrag dieser Art mit Binnenreim in der Überschrift //

Technisches

Länge, Format

Die RecordId eines Salesforce Objektes hat 2 Formate:

  • 15 Stellen, base62 [0-9a-zA-Z] - das heißt alle Zahlen und Buchstaben, Groß- und Kleinschreibung wird unterschieden: 0019000000B98de

oder

  • 18 Stellen, alle Zahlen und Buchstaben, Groß- und Kleinschreibung wird ignoriert: 0019000000B98DeAAB
    • 15 Stellen sind die "Normalform" der Record Id. Sie wird so in der UI verwendet, zum Beispiel in Links oder Reports. Die API hingegen liefert
    • 18 Stellen, die man auch mittels CASESAFEID(Id) Formelfeld in der UI generieren kann. Leider gibt es keine Entsprechung zu dieser Formel auf Apex Level, daher im Anhang ein CodeSnippet dafür.
  • Hintergrund für diese zwei äquivalenten Ids scheint historisch begründet - die Unterscheidung zwischen Groß- und Kleinschreibung auf API Ebene ist nicht zwingend für alle Integrationen gegeben.
  • Um von der 18-Stellen Id auf die 15-stellige zu kommen, reicht es die letzten 3 Zeichen rechts abzuschneiden.
    Die Account ID 0019000000B98deAAB wird zu 0019000000B98de.

Aufbau

Allen Ids folgen dem Aufbau:

aaabbcddddddddd

Analytisches

  • 238.328 verschiedene Objekte sind mit drei Stellen Objekt Identifier möglich
  • mindestens 245 davon sind von Standard Objekten belegt (siehe unten).
  • Ein genauerer Blick lohnt sich, denn die Art und Weise wie die IDs geclustert sind, gibt Aufschluß über die Objekt-Zusammenhänge und Entwicklung. So gehören Contract, Order, OrderItem und Approval historisch eng zusammen 800, 801, 802, 806
  • Regelmäßiges Überprüfen neuer RecordIds hilft, einen besseren Überblick über Veränderungen zu erhalten. So ist 0Er:PlattformCachePartition ein ziemlich neues Objekt.
  • Die neun Stellen ddddddddd reichen für mehr als 13 Billiarden Objekte. (13.537.086.546.263.552 um genau zu sein)

13 Billiarden hört sich nach viel an, ist aber ziemlich wenig, wenn man über Big Data oder Internet of Things nachdenkt und bald jeder Schnürsenkel eine eigene Id in meiner Org braucht.
Opfert Salesforce die POD Id bb (über den Aufwand will ich nicht nachdenken) und die Stelle future use c erhöht sich die Anzahl möglicher Objekte auf 3 Trilliarden (3.226.266.762.397.899.821.056)

Im Anhang folgt eine komplette Liste von Prefixes zu StandardObjekten, Stand Spring 16. Außerdem zwei Code Snippets - sfdc15To18() und mapIdPrefixToSobjectName()

Appendix

Konvertieren von 15stelliger ID zu 18 Stellen via Apex

public static String sfdc15To18 (String original15) {
// This method expects a 15-char valid Salesforce ID, and returns the 18-char equivalent

Map<String,String> lookup5bin = new Map<String,String>();
String Piece1 = '';
String Piece2 = '';
String Piece3 = '';

original15 = original15.substring(0,15);

lookup5bin.put('00000','A'); lookup5bin.put('01000','I'); lookup5bin.put('10000','Q'); lookup5bin.put('11000','Y');
lookup5bin.put('00001','B'); lookup5bin.put('01001','J'); lookup5bin.put('10001','R'); lookup5bin.put('11001','Z');
lookup5bin.put('00010','C'); lookup5bin.put('01010','K'); lookup5bin.put('10010','S'); lookup5bin.put('11010','0');
lookup5bin.put('00011','D'); lookup5bin.put('01011','L'); lookup5bin.put('10011','T'); lookup5bin.put('11011','1');
lookup5bin.put('00100','E'); lookup5bin.put('01100','M'); lookup5bin.put('10100','U'); lookup5bin.put('11100','2');
lookup5bin.put('00101','F'); lookup5bin.put('01101','N'); lookup5bin.put('10101','V'); lookup5bin.put('11101','3');
lookup5bin.put('00110','G'); lookup5bin.put('01110','O'); lookup5bin.put('10110','W'); lookup5bin.put('11110','4');
lookup5bin.put('00111','H'); lookup5bin.put('01111','P'); lookup5bin.put('10111','X'); lookup5bin.put('11111','5');

Piece1 = sfdc0Or1(original15.substring(4,5)) +
sfdc0Or1(original15.substring(3,4)) +
sfdc0Or1(original15.substring(2,3)) +
sfdc0Or1(original15.substring(1,2)) +
sfdc0Or1(original15.substring(0,1));

Piece2 = sfdc0Or1(original15.substring(9,10)) +
sfdc0Or1(original15.substring(8,9)) +
sfdc0Or1(original15.substring(7,8)) +
sfdc0Or1(original15.substring(6,7)) +
sfdc0Or1(original15.substring(5,6));

Piece3 = sfdc0Or1(original15.substring(14,15)) +
sfdc0Or1(original15.substring(13,14)) +
sfdc0Or1(original15.substring(12,13)) +
sfdc0Or1(original15.substring(11,12)) +
sfdc0Or1(original15.substring(10,11));

return (original15 + lookup5bin.get(Piece1) + lookup5bin.get(Piece2) + lookup5bin.get(Piece3));

}

Erstellen einer Liste von PrefixIds - Objektname:

public static Map<String,String> mapIdPrefixToSobjectName(){
	Map<String, String> mapIdPrefixToSobjectName = new Map<String, String>();
    Map<String, Schema.SObjectType> mapObjNameToSobjectDescribe = Schema.getGlobalDescribe(); 
		for(String strSobjectName : Schema.getGlobalDescribe().keySet()){
		   Schema.DescribeSObjectResult dscrResult =  mapObjNameToSobjectDescribe.get(strSobjectName).getDescribe();
		   String strObjName = dscrResult.getName();
		   String strObjIdPrefix = dscrResult.getKeyPrefix();
		  // If it ain't got no Id, I'm not interested
            If (strObjIdPrefix != NULL ){
            System.debug('['+strObjName + '], ['+ strObjIdPrefix+']');
            mapIdPrefixToSobjectName.put(strObjIdPrefix,strObjName);
            }
		}
    return mapIdPrefixToSobjectName;
}
//Debug Produces: 
//13:32:53.2 (164554358)|USER_DEBUG|[9]|DEBUG|[WorkFeedbackQuestionSet],[0W8]

Standard Objekte Id Prefix Tabelle (Spring 16)

Id PrefixsObject Name
001Account
002Note
003Contact
005User
006Opportunity
008OpportunityHistory
00aCaseComment
00aIdeaComment
00bWebLink
00BListView
00DOrganization
00EUserRole
00eProfile
00GGroup
00IPartner
00JOpportunityCompetitor
00KOpportunityContactRole
00kOpportunityLineItem
00lFolder
00OReport
00PAttachment
00QLead
00rAccountShare
00tOpportunityShare
00TTask
00UEvent
00vCampaignMember
00XEmailTemplate
010CaseSolution
011GroupMember
012RecordType
015Document
016BrandTemplate
018EmailStatus
019BusinessProcess
01aDashboardComponent
01HMailmergeTemplate
01JOpportunityStage
01JLeadStatus
01kFieldPermissions
01mBusinessHours
01NScontrol
01nCaseShare
01oLeadShare
01pApexClass
01QAssignmentRule
01qApexTrigger
01sPricebook2
01tProduct2
01uPricebookEntry
01YCampaignMemberStatus
01ZDashboard
022FiscalYearSettings
026Period
02aContractContactRole
02iAsset
02nCategoryNode
02oCategoryData
02sEmailMessage
02ZAccountContactRole
03gQueueSobject
03jCaseContactRole
03sContactShare
03uUserPreference
04aProcessDefinition
04bProcessNode
04FLoginGeo
04gProcessInstance
04hProcessInstanceStep
04iProcessInstanceWorkitem
04mAdditionalNumber
04vCallCenter
050PackageLicense
051UserPackageLicense
058ContentWorkspace
059ContentWorkspaceDoc
05aDataStatistics
05DContentDistribution
05FApexTestSuite
05HContentDistributionView
05XDocumentAttachmentMap
066ApexPage
068ContentVersion
069ContentDocument
069ContentNote
06AContentDocumentLink
06dGrantedByLicense
06EDandBCompany
06iFlexQueueItem
06jApexEmailNotification
074CorsWhitelistEntry
07gActionLinkGroupTemplate
07HContentFolder
07IContentFolderMember
07LApexLog
07lActionLinkTemplate
07MApexTestResult
07pUserAppMenuItem
07TAuthConfig
07uUserEntityAccess
07UAuthConfigProviders
07vContentFolderLink
081StaticResource
083Vote
087Idea
08aCronJobDetail
08CDatacloudContact
08eCronTrigger
08MFeedAttachment
08PBackgroundOperation
08sCampaignShare
08UFeedRevision
091EmailServicesFunction
093EmailServicesAddress
099ApexComponent
09aCommunity
09AFeedPollChoice
09BFeedPollVote
09FDatacloudPurchaseUsage
09KDatacloudCompany
09NDatacloudDandBCompany
09ODatacloudOwnedEntity
09PEmailDomainKey
09XDcSocialProfileHandle
09YDcSocialProfile
0AaCollaborationGroupRecord
0AbAuraDefinitionBundle
0AdAuraDefinition
0AkAuthSession
0ATEventLogFile
0BmDuplicateRule
0BsDatacloudSocialHandle
0BtAnnouncement
0C0Holiday
0caChatterActivity
0CPCustomPermission
0CQOauthToken
0D2OrgWideEmailAddress
0D5FeedItem
0D6FeedTrackedChange
0D7FeedComment
0DdListViewChart
0DeListViewChartInstance
0DMSite
0DSAppMenuItem
0E8EntitySubscription
0ElInstalledMobileApp
0ErPlatformCachePartition
0EvPlatformCachePartitionType
0F9CollaborationGroup
0FBCollaborationGroupMember
0FoFlowInterview
0FTTopicAssignment
0FyOrderShare
0GKDuplicateRecordSet
0GLDuplicateRecordItem
0H1CollaborationInvitation
0H4ConnectedApplication
0HdTestSuiteMembership
0HPUserProvisioningRequest
0HsUserProvisioningLog
0HXUserProvMockTarget
0HYUserProvAccountStaging
0I0FeedLike
0I4Domain
0I5CollaborationGroupMemberRequest
0IFPushTopic
0inKnowledgeableUser
0J0SetupEntityAccess
0JDMatchingRule
0JeUserProvisioningConfig
0JEMatchingRuleItem
0JfDomainSite
0JiMacroInstruction
0JrThirdPartyAccountLink
0JuRelationshipInfo
0JUUserListViewCriterion
0JvRelationshipDomain
0JVPlatformAction
0JZMacro
0LESamlSsoConfig
0M6StreamingChannel
0MDSearchPromotionRule
0N2UserShare
0NaUserListView
0NBSecureAgent
0NDSecureAgentPlugin
0NESecureAgentPluginProperty
0NiUserProvAccount
0NvEntityParticle
0NwUserAppMenuCustomization
0OOProcessInstanceNode
0PaPermissionSetAssignment
0PDCustomPermissionDependency
0PLPermissionSetLicense
0PSPermissionSet
0QtVerificationHistory
0QySecureAgentsCluster
0REEventRelation
0SOAuthProvider
0TOTopic
0UTTenantUsageEntitlement
0W7WorkPerformanceCycle
0W8WorkFeedbackQuestionSet
0WAWorkFeedbackQuestion
0WBWorkFeedback
0WCWorkFeedbackRequest
0WDWorkCoaching
0WIGoal
0WJMetric
0WKGoalLink
0WLWorkFeedbackTemplate
0WMMetricDataLink
0XANamedCredential
0XCExternalDataSource
0XUExternalDataUserAuth
0YaLoginHistory
0YmSetupAuditTrail
0YwUserLogin
100UserLicense
110ObjectPermissions
1CAAccountCleanInfo
1CCContactCleanInfo
1CLLeadCleanInfo
2LAPermissionSetLicenseAssign
3NACustomObjectUserLicenseMetrics
4coSearchLayout
4dtDataType
4feFieldDefinition
4fpUserFieldAccess
4ieEntityDefinition
4pbPublisher
4pvPicklistValueInfo
500Case
501Solution
608ForecastShare
701Campaign
707AsyncApexJob
709ApexTestQueueItem
710LoginIp
713ClientBrowser
800Contract
801Order
802OrderItem
806Approval