In my example scenario, I've created a validation rule against the Contact standard object that checks either the contact's email address or phone number has been provided:
All well and good. However, what about the situation where I am creating a Contact programmatically? In this case the validation rule is still applied:
Obviously creating via the system log is a contrived example, but in practice I may be receiving the details from an external system as part of an integration (via an apex web service) or data migration (via the Apex Data Loader), and the information may simply not be available in that system. If its a data migration, I could disable the validation rule for the duration, but if its a real-time integration that isn't an option.
The solution I came up with was to provide a mechanism for the record itself to indicate how it was being created/edited and to take that into account for in the validation rule.
The first step in the solution is to create a new custom field on the Contact object - a checkbox that if set to true indicates the record is being processed in an apex context. This checkbox is not made available on any page layouts, as we don't want regular UI users to be able to check it.
Next, change the validation rule to allow both the email and phone fields to be empty if the apex context field is set to true:
Its tempting at this time to think that the problem is now solved - the Apex Context field can simply be set to true and the validation rule will allow the record through. However, the record will then be saved to the database with the Apex Content field set to true, and the next time that a user edits the record in the UI, the validation rule will be bypassed - not the behaviour I am looking for. Therefore I've created a workflow rule and associated field update to unset the checkbox whenever it is found to be set.
and that's all there is to it. Now I can create a contact via the system log without providing the email or phone field:
But if I then navigate to that contact via the UI and attempt to edit the record without providing these fields, the validation rule blocks this: