7

When a DML operation on a list of records of a concrete object type, e.g. Account fails, calling getDmlFields on the thrown DMLException returns the fields that caused the failure, as described in the docs.

But when a DML operation on a List<SObject> fails, getDmlFields returns null.

Here's an example:

force apex <<EOF
try {
   insert new List<Account>{new Account()};
} catch (DMLException e) {
   for (Integer i = 0; i < e.getNumDml(); i++) {
      System.debug('FAILED INSERTING ACCOUNT');
      System.debug('ERROR FIELD NAMES');
      System.debug(e.getDmlFieldNames(i));
      System.debug('ERROR FIELDS');
      System.debug(e.getDmlFields(i));
   }
}
try {
   insert new List<SObject>{new Account()};
} catch (DMLException e) {
   for (Integer i = 0; i < e.getNumDml(); i++) {
      System.debug('FAILED INSERTING SOBJECT');
      System.debug('ERROR FIELD NAMES');
      System.debug(e.getDmlFieldNames(i));
      System.debug('ERROR FIELDS');
      System.debug(e.getDmlFields(i));
   }
}
EOF

In both cases, a validation rule on the Type field causes the insert to fail. The call to getDmlFieldNames returns Type in both cases, but in the second case, the call to getDmlFields returns null.

15:41:36.15 (39209292)|CODE_UNIT_STARTED|[EXTERNAL]|Validation:Account:new
15:41:36.15 (39398837)|CODE_UNIT_FINISHED|Validation:Account:new
15:41:36.15 (40276287)|EXCEPTION_THROWN|[2]|System.DmlException: Insert failed. First exception on row 0; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, Type is required for Referral Accounts: [Type]
15:41:36.15 (40838118)|USER_DEBUG|[5]|DEBUG|FAILED INSERTING ACCOUNT
15:41:36.15 (40861711)|USER_DEBUG|[6]|DEBUG|ERROR FIELD NAMES
15:41:36.15 (40965320)|USER_DEBUG|[7]|DEBUG|(Type)
15:41:36.15 (40987483)|USER_DEBUG|[8]|DEBUG|ERROR FIELDS
15:41:36.15 (41104191)|USER_DEBUG|[9]|DEBUG|(Type)
15:41:36.15 (43357699)|CODE_UNIT_STARTED|[EXTERNAL]|Validation:Account:new
15:41:36.15 (43515984)|CODE_UNIT_FINISHED|Validation:Account:new
15:41:36.15 (44175767)|EXCEPTION_THROWN|[13]|System.DmlException: Insert failed. First exception on row 0; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, Type is required for Referral Accounts: [Type]
15:41:36.15 (44572412)|USER_DEBUG|[16]|DEBUG|FAILED INSERTING SOBJECT
15:41:36.15 (44591105)|USER_DEBUG|[17]|DEBUG|ERROR FIELD NAMES
15:41:36.15 (44656270)|USER_DEBUG|[18]|DEBUG|(Type)
15:41:36.15 (44676099)|USER_DEBUG|[19]|DEBUG|ERROR FIELDS
15:41:36.15 (44719764)|USER_DEBUG|[20]|DEBUG|null

Is this expected behavior or a Salesforce bug?

4
  • Interesting question. Funny thing is, I tried to replicate, but even the first case (the one typed to Account) is not returning any values for getDmlFields or getDmlFieldNames. Puzzling...
    – mkorman
    Commented May 8, 2016 at 13:44
  • @mkorman, what error do you get? (My example used a custom validation rule.)
    – xn.
    Commented May 9, 2016 at 15:29
  • I created a validation rule as well (Name must be longer than 10 characters). I got a DML exception; however, when I printed the contents of getDmlFields and names, there was just 1 row, with blank/null values.
    – mkorman
    Commented May 9, 2016 at 15:51
  • Did you configure the Error Location to show the error on the Name field? I'm seeing the same behavior with a validation rule on Name as on Type.
    – xn.
    Commented May 9, 2016 at 17:42

1 Answer 1

3

According to support, this is as designed, although it seems more like an oversight than a design decision to me. In any case, it should be documented.

From support:

The behavior that we see when we are using List is working as designed. Please find the detailed summary for the same below

-- The getDMLFieldName's return type is String[] whereas getDMLFields return type is Schema.sObjectField[]

which means the getDMLFields has to make a describe call to get the fields. The describe call looks something like follows

Account.sObjectType.getDescribe();

We need concrete SObject Types like Account or Opportunity to get this Describe call working. As Heterogeneous list List cannot be used to get the instance and map it to the describe call.

Hence kindly use Homogeneous List types like List or List to get the getDMLFields() working.

As a work-around, you can get the SObjectField if you keep a reference to the list of SObjects on which the failed DML operation was performed.

List<SObject> sobjects = new List<SObject>{new Account()};
try {
   insert sobjects;
} catch (DMLException e) {
  for (Integer i = 0; i < e.getNumDml(); i++) {
    // Get the list of field names, which may not be globally unique,
    // but will be unique for a single SObject
    List<String> fieldNames = e.getDmlFieldNames(i);
    // Get the SObjectType for the record that failed
    Integer insertIndex = e.getDmlIndex(i);
    Schema.SObjectType failedType =   sobjects[insertIndex].getSObjectType();
    for (String fieldName : fieldNames) {
      // Use the field name to get the SObjectField
      Schema.SObjectField fieldFromName = failedType.getDescribe().fields.getMap().get(fieldName);
      System.debug('SOBJECT FIELD FROM NAME');
      System.debug(fieldFromName);
    }
  }
}
2
  • Are you able to quote support directly?
    – Adrian Larson
    Commented May 12, 2016 at 21:18
  • 1
    "We believe that its working as designed and it has to do with describe call while access metadata. However I am discussing this case with our Internal Team for some concrete information based on which we can identify the behavior of DMLException.getDmlFields when we use <sobject>." I'll update the answer here if I get a better solution than my work-around from support.
    – xn.
    Commented May 12, 2016 at 21:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .