Idiosyncrasies of Salesforce Database.Upsert with List of SObject

Recently, I had to create a generic framework that used Salesforce’s Database.upsert method with a generic list<SObject> since the records could be of any type. While implementing the desired functionality, various unexpected errors occurred. In this post, we’ll take a look at these various idiosyncrasies.

External Id With No “AllOrNothing” Error

When one tries to call Database.upsert using a generic list<SObject> with an external id field, the following runtime exception occurs: “System.TypeException: DML on generic List<SObject> only allowed for insert, update or delete”

The gist below demonstrates this.

External Id With No “AllOrNothing” Fix

The fix is to dynamically instantiate the List<SObject> variable to a list of the concrete SObject Type.

External Id With “AllOrNothing” Error

Database.upsert has an optional “AllOrNothing” boolean parameter that when set to false allows records that succeed to be persisted while those that error to not be persisted. When that parameter is specified with a List<SObject> and an external id, one receives the following compile time error: “Compile Error: Upsert requires a concrete SObject type at line ## column ##”

External Id With “AllOrNothing” Fix

There are at least two “workarounds”.

One is to manually do the upsert in the code. I.E. you’re writing the upsert logic in Apex instead of letting Salesforce handle it.

The other workaround is to dynamically generate a class at runtime that has an upsert method that dynamically casts a List<SObject> to a list of a concrete type and invoke the appropriate upsert call. Here’s a gist of what that looks like:

Neither workaround is particularly elegant but manually doing the upsert may be easier to implement and maintain.

What other challenges have you faced with Database.upsert and a List<SObject>? Do you have any other solutions?

Happy Coding,

Luke

Convention Over Configuration

Configuration

Configuration is data that tells the system how to function. It often can be changed while the system is running to do something else. Configuration is good because the system isn’t hard-coded in its behavior and can be changed based on the allowable configuration options.

One major consideration with configuration is volume. There are systems with so much configuration that managing the configuration takes a lot of time and overhead. With Microsoft applications, I’ve seen this with configuration spread among config files, databases, and other data sources. In Salesforce, the configuration is usually in Custom Settings, Objects, and Custom Metadata Types. The overhead comes from not just developing the software to support the various options but documenting the configuration options and training others about the options too.

“Convention Over Configuration” Design Principle

A Convention is a standard or agreed upon way of doing things. In the software context, if things are done a certain way, the software will behave this way without having to be configured to do so.

Running Tests Example

In my Automated Unit Test Execution Salesforce Cookbook Recipe, the code runs apex classes that start with “Test”. As long as someone creates a new test class with the naming convention “Test<class_name>”, their tests will automatically run without having to tell the system to do so.

ASP.NET MVC Example

In ASP.NET MVC, views are automatically bound to their corresponding data entities as long as the same name is used in the view and the binding property on the underlying entity. This is great because in ASP.NET WebForms and other web frameworks, a decent amount of scaffolding code was marshalling the data from the view to the model and vice-versa.

Other Considerations

Whenever possible, I prefer to use convention over configuration to ease software overhead. However, there may be convention exceptions that need to be considered so the software can behave differently from the convention. This can be implemented with convention overrides or with configuration using a hybrid approach. I.E. convention and configuration.

As with any design principle, “convention over configuration” has to be considered in the context of the system in which it’s used to see if it makes sense to use.

What do you think of “Convention Over Configuration”? What other examples do you have? Do you have other patterns that drive system behavior without configuration?

Happy Coding,

Luke