+ Start a Discussion
rcardosorcardoso 

Get de existing ID from a DmlException: DUPLICATE_VALUE

Hi!

 

I'm trying to get the existing ID when a DmlException: DUPLICATE_VALUE is throw.

but i'm getting null.

my code looks like this: 

Case c = new Case();
//set some fields
try{
  insert c;
}catch(DmlException e){
  if(e.getDmlType(0) == StatusCode.DUPLICATE_VALUE){
    return e.getDmlId(0); //its null here! =(
  }else{
    throw e;
} } return c.id;

 

I could to put a

c = [Select id from Case where other_fields = other_values];

but i can't be sure if it will get the same record.

 

If I check the logs i find: 

System.DmlException: Upsert failed. First exception on row 0; first error: DUPLICATE_VALUE, duplicate value found: Claim_id__c duplicates value on record with id: 500J0000001ylwB: []

 

Any ideas how do i get the id without manipulating the message string? 

500J0000001ylwB
Best Answer chosen by Admin (Salesforce Developers) 
sfdcfoxsfdcfox
When inserting, if there is an error, no ID will be assigned. e.getDmlId(0) is the record that was attempted to be inserted, not the conflicting ID (e.g. it will always be null for failed inserts; you need to use the getDmlIndex method to get the index of the failed row).

You could call getDmlFields to determine the fields which failed. From there, you could construct a query to find the duplicated value (SELECT Id FROM Case WHERE Claim_id__c = :c.Claim_Id__c). Short of using a query, I don't see any specific way to reliably determine the error just from the getMessage() function.

All Answers

sfdcfoxsfdcfox
When inserting, if there is an error, no ID will be assigned. e.getDmlId(0) is the record that was attempted to be inserted, not the conflicting ID (e.g. it will always be null for failed inserts; you need to use the getDmlIndex method to get the index of the failed row).

You could call getDmlFields to determine the fields which failed. From there, you could construct a query to find the duplicated value (SELECT Id FROM Case WHERE Claim_id__c = :c.Claim_Id__c). Short of using a query, I don't see any specific way to reliably determine the error just from the getMessage() function.
This was selected as the best answer
JayNicJayNic

I would just interpret the string... You know the object prefix id, so you can just do a string match against '500' and grab the 18 characters.

If you need the name of the record as well: then you need to do a query.

rcardosorcardoso

Hey thank you guys,

 

I did what 

 

sfdcfoxsfdcfox
The system won't allow duplicated values on a unique field, even in the concurrent situation. Salesforce is engineered to keep transactions locked for as short a time as possible, so it's difficult to actually test this, but I'd wager that in the event of duplicate entries, the second transaction would suspend itself until the first transaction completes (so that Salesforce can definitively state if there is a duplicate value).

In practice, this probably shouldn't matter, but in theory, a long-running transaction might cause a "UNABLE_TO_LOCK_ROW" error on the second transaction. The user that receives the error would just have to try to submit again.
Suraj PSuraj P
Here's some code that might help:
 
Pattern idMatch = Pattern.compile('^.*\\b([0-9a-zA-Z]{15,18})\\b.*$');
DMLException dex = (DMLException)ex;
if(dex.getDmlMessage(0).toLowerCase().indexOf('duplicate')>-1){
   Matcher idMatcher = idMatch.matcher(dex.getDmlMessage(0));
   if(idmatcher.matches() && idmatcher.groupCount()>0){
      Id recordId = Id.valueOf(idmatcher.group(1));
   }
}