1

The various DML operations (insert, update, delete, etc.) all return results with very similar methods and properties.

It is not uncommon, as a developer, that I should want to handle these results in similar ways.

Is there an interface that I can compose to instead of the concretions?

4

No, they do not implement a common interface. As a workaround to this, I created a wrapper class that does this:

class DmlResult {
    Id recordId;
    Integer rowIndex;
    Boolean success;
    Database.Error[] errors;
    DmlResult(Boolean success, Id recordId, Database.Error[] errors, Integer rowIndex) {
        this.success = success;
        this.recordId = recordId;
        this.errors = errors;
        this.rowIndex = rowIndex;
    }
}

From there, I have a DmlResultList class that normalizes the data:

class DmlResultList implements Iterable<DmlResult> {
    DmlResult[] genResults;
    DmlResultList(Database.SaveResult[] results) {
        genResults = new DmlResult[0];
        for(Database.SaveResult result: results) {
            genResults.add(new DmlResult(result.isSuccess(), result.getId(), result.getErrors(), genResults.size()));
        }
    }
    DmlResultList(Database.DeleteResult[] results) {
        genResults = new DmlResult[0];
        for(Database.DeleteResult result: results) {
            genResults.add(new DmlResult(result.isSuccess(), result.getId(), result.getErrors(), genResults.size()));
        }
    }
    // ... other result types
}

Once you have this, you can then create a common handler:

DmlResultList results = new DmlResultList(Database.insert(records, false));
  • Ive come up with a similar solution, but then, of course, we need to iterate over the list to perform the conversion and we are instantiating a lot of objects... I was hoping we can avoid that.... – Brian Kessler Nov 4 '18 at 18:42
3

There is no interface implemented by the various Database.*Result classes, which do all implement mostly the same methods (the exception being Database.UpsertResult, which has one additional method).

However, the classes are serializable, as is the underlying Database.Error. So what you can do is create your own unified class implementing the same "interface" (data model, really), serialize your Database.*Results to JSON, and then deserialize them into your own class, to avoid writing any non-generic code.

You are, of course, taking the performance hit (which I have not myself measured) of performing JSON serialization and deserialization around all of your DML operations.

Unified Class

public class DatabaseResult {
    public class Error {
        public String statusCode;
        public String message;
        public List<String> fields;
    }
    public Id id;
    public Boolean success;
    public List<Error> errors;
}

Example Code

Account a = new Account();

Database.SaveResult[] srs = Database.insert(new List<Account>{a}, false);

System.debug('Toto: ' + JSON.serializePretty(srs));
System.debug('Ea: ' + JSON.serializePretty(srs[0]));

DatabaseResult q = (DatabaseResult )JSON.deserialize(JSON.serializePretty(srs[0]), DatabaseResult.class);
System.debug('Q: ' + JSON.serializePretty(q));
  • 1
    Great minds think alike. – sfdcfox Nov 4 '18 at 11:36
  • I'm more comfortable with your solution; bouncing between JSON and the object model always feels a bit fragile to me. – David Reed Nov 4 '18 at 11:40
  • Cheers for the response... I already had a solution similar to Sfdcfoxs... I was hoping there would be an interface we could use to improve upon it. – Brian Kessler Nov 4 '18 at 18:46

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.