28

I need to be able to check if an org has Person Accounts enabled via Apex Code as part of package. What's the best way to do this without making the package require Person Accounts be enabled in any org in which it's installed?

35

Update

New Method

As of API version 38.0 they've added a new method to the DescribeSObjectResult class getHasSubtypes(). From the documentation: DescribeSObjectResult.getHasSubtypes()

Indicates whether the object has subtypes. The Account object, which has subtype PersonAccount, is the only object that will return true.

This method runs in <1ms and when tested with multiple calls it's an order of magnitude faster than checking the Account fields directly.

// Check to see if person accounts are enabled.
public Boolean personAccountsEnabled()
{
    // You can call either getHasSubtypes() or access it like a property.
    return Account.SObjectType.getDescribe().hasSubtypes;
}

Previous methods:

Method 1

Try to access the isPersonAccount property on an Account and catch any exception that occurs if that property is missing. If an exception is generated then person accounts are disabled. Otherwise they're enabled. To avoid making person accounts required for the package you assign the Account object to an sObject and use sObject.get( 'isPersonAccount' ) rather than accessing that property directly on the Account object.

This method takes ~3.5ms and negligible heap space in my testing.

// Test to see if person accounts are enabled.
public Boolean personAccountsEnabled()
{
    try
    {
        // Try to use the isPersonAccount field.
        sObject testObject = new Account();
        testObject.get( 'isPersonAccount' );
        // If we got here without an exception, return true.
        return true;
    }
    catch( Exception ex )
    {
        // An exception was generated trying to access the isPersonAccount field
        // so person accounts aren't enabled; return false.
        return false;
    }
}

Method 2

Use the account meta-data to check to see if the isPersonAccount field exists. I think this is a more elegant method but it executes a describe call which counts towards your governor limits. It's also slightly slower and uses a lot more heap space.

This method takes ~7ms and ~100KB of heap space in my testing.

// Check to see if person accounts are enabled.
public Boolean personAccountsEnabled()
{
    // Describe the Account object to get a map of all fields
    // then check to see if the map contains the field 'isPersonAccount'
    return Schema.sObjectType.Account.fields.getMap().containsKey( 'isPersonAccount' );
}
  • 2
    I prefer Method 2. The heap space shouldn't be a concern - it's freed after the function exits. In practice you'll want to cache the result in a static variable so you don't make a describe call every time you check in a context. So it's only one Describe call per execution context. Plus, in a larger app you can use a single Describe to check for other fields that may or may not be present (such as DunsNumber, RecordType) so you may be making the call anyway. Besides, as you say - #2 is more elegant :-) – kibitzer Aug 31 '12 at 20:00
  • 2
    Yeah, I was going to mention caching the variable at the end of the response for exactly that reason but forgot to tack that on. For me, 100KB of heap can be problematic at times depending on when it happens and 3.5ms extra execution time is also an issue for me since in my application a lot of work has to be done in triggers so every little bit of optimization helps. I listed them both since #1 fits my needs more closely but #2 is more elegant and probably a more correct way of solving the problem. – E.J. Wilburn Aug 31 '12 at 20:09
  • Great answer! I tend to agree with #2 since there are other possible ways that an exception can get thrown (or could be introduced into the code later) which would produce a false positive, where the describe approach is very specific. But of course, there's always the limits to consider, and perhaps by being more specific in the exception handling you could distinguish between any general error and an SObjectException error (ie: System.SObjectException: Invalid field isPersonAccount for Account). – Adam Sep 1 '12 at 18:23
  • Updated with a better method that was added in API 38.0. – E.J. Wilburn Feb 15 '18 at 4:40

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.