DML: Standalone Statements or Database Methods Which One to Use? - El Toro - Find articles about Visualforce, Apex, Force.com and Salesforce in general

Print Preview

DML: Standalone Statements or Database Methods Which One to Use?

Salesforce allows you to perform DML operations as either standalone calls or methods, and because the can behave very differently with regards to how you handle the errors and which records will commit, it’s important to understand them properly to determine how you would like to write your code.

Syntax

The standalone statements are similar in syntax to some keywords used in Apex, specifically the return statement because it just uses a verb and the expression to execute. They look like this:

Insert myAccount;
Update myAccounts;

On the other hand the database methods use a syntax which is similar to a method call. They look like this:

Database.Insert(myAccount);
Database.update(myAccounts);

Note: It is also possible to have a second parameter (AllOrNone) in the database methods to indicate which records you want to commit if there are errors with some of the records.

Differences

As mentioned before, the differences are in two categories: How you should handle the errors, and which records will be committed. This table summarizes these differences:

The header column indicates the records you want to insert to the database. Here we have 5 account records, and let’s assume 2 of them (2nd and 4th) will fail some validation rule or you call the addError() method either on the record/field.

The other four columns indicate the way you are going to insert the records (as indicated in the header row).

As indicated in the fourth column, when you use the Database.insert(acs, false) Salesforce.com will commit the good records but will not commit the bad records (remember the second parameter is called AllOrNone). In any other operation you perform, Salesforce.com does not commit the good records (and obviously, it can’t commit the bad records).

The second difference is how you should handle the errors. The first three columns (standalone, method with no parameters or method with second parameter TRUE) will throw a DMLException with information about the two failed records, but the last column (method with false parameters) will return a collection of List<SaveResult> with information for all the five records you submitted.

DMLException

When you get a DMLException, you will get information for the failed records only, so you may have to work with a shorter set of data (assuming some records did not fail), so you need to maintain two indexes in your code. You can use this code as a template:

List<Account> acs = new List<Account>();
acs.add(new Account());
try {
	insert acs;
} catch (System.DMLException ex) {
	String msg = '';
	for (Integer exceptIdx = 0; exceptIdx < ex.getNumDml(); exceptIdx++) {
		Integer dataIdx = ex.getDmlIndex(exceptIdx);
		msg += 'Account: ' + acs[dataIdx].Name + ' failed!';
		msg += 'Error Type: ' +  ex.getDmlType(exceptIdx);
		msg += 'Error Message: ' +  ex.getDmlMessage(exceptIdx);
		msg += 'Fields with errors: ' + ex.getDmlFieldNames(exceptIdx);
		msg += '\r\n';
	}
	System.debug(msg);
}

List<SaveResult>

When you work with the List<SaveResult> you will information for all the records (failed or not), so you will have a set of data of exactly the same size of the original set of data records, so you only need to maintain one index, but check if the particular record was successful or not. You can use this code as a template:

List<Account> acs = new List<Account>();
acs.add(new Account());
List<Database.SaveResult> srs = Database.insert(acs, FALSE);
String msg = '';
for(Integer idx = 0; idx < srs.size(); idx++) {
	Database.SaveResult sr = srs[idx];
	if (!sr.isSuccess()) {
			msg += 'Account: ' + acs[idx].Name + ' failed!';
			for (Database.Error er : sr.getErrors()) {
				msg += 'Error (' +  er.getStatusCode() + '):' + er.getMessage();
				msg += '\r\n';
			}
	}
}
System.debug(msg);

comments powered by Disqus

© El Toro . IT @ 2013
Andrés Pérez