Part 3: Special Relationship Tools - Archive of IC Blog

In this post we’re going to explore how Salesforce provides us with additional relationship tools in the form of tweaking some standard types and providing some non-standard. It’s all pretty exciting. 

Accounts, Opportunities and Contacts (who doesn’t like quizzes?)

Pop quiz time!

  1. What is the relationship type between the Opportunity and Account object?
  2. What is the relationship type between the Contact and Account object?

Master-detail, right? And why not—these objects must be tightly coupled. In fact, we can create a rollup field on Account to summarize Opportunities.

Both relationships are actually lookups(for real!).

All About the Opportunity

What? Wait, we can do roll-ups on Account for Opportunities—how does that work when it’s a lookup? If we consider it from a business use case perspective, Opportunity ownership needs to be independent from Account ownership (it is very common for larger businesses to have multiple sales teams working the same Account: consider two sales teams, one is responsible for selling the product and the other replacement parts or warranty coverage). If the relationship was master-detail there wouldn’t be a way to allow different owners for Opportunities (remember: the child in a master-detail relationship has no visible owner). And having the ability to roll up on the Opportunity to the Account is incredibly useful—as a result Salesforce has extended the ability to do roll-ups on this one lookup relationship (there is an idea to allow roll-ups on all lookups:

Contacts Without an Account?

With the Contact to Account relationship as a lookup Salesforce does allow Contacts to be created without an associated Account. These are referred to as ‘private’ Contacts and normally are only visible to their owner and system administrators (the sharing rules from them are a bit different). We can allow others to see private Contacts by granting users ‘View All’ for Contacts or ‘View All Data’ (tread lightly with either access—especially the latter option which opens visibility to all objects, not just Contacts). There is no standard functionality on Account that allows us to do rollups for Contacts.

Let’s All Standardize on Standard Relationships

To make it simpler, all the relationships between standard objects—and only between standard objects—should be considered as lookups, except when Salesforce sprinkles in some special mojo. Just a reminder: this doesn’t prevent most standard objects from being part of a custom master-detail relationship as long as it is on the master side (parent) of the relationship.

The Special Mojo

To allow for flexibility, the platform allows for some special types of relationships (that mojo we just talked about). We are not allowed to create these relationships; though we can leverage them.

1. Polymorphic (also known as cross-reference):

Up to this point we’ve been exploring how a child object will point to a parent object; implying that the child can only be related to a single parent object. If we needed to have a child object relate to two different parent objects we would need to create two different relationships—one for each. This applies for any custom relationship we want to create.

There are some standard objects that relate to many different objects. The best example is Activity (which is really a façade for two objects: Events and Tasks; perhaps a subject for another post). When we create a new custom object the platform prompts us with the option to allow it to have Activities—which translates into both Activity objects (again, Event and Task) being related to this new custom object. To avoid creating a new lookup from Event and Task to point to newly created custom objects Salesforce instead utilizes polymorphic reference fields—fields that can associate to more than one object as in this example:

That’s a ton of objects!

There are two polymorphic fields on the Activity objects: whoId and whatId. WhoId references both Contact and Lead; WhatId points to any other objects that are configured to have related Activities (as seen above). Another example of a polymorphic field is the owner field:

On some objects the owner can either be a user or a queue (technically a queue is a group–hence the field definition identifies the relationship as polymorphic for User and Group). Check out this more technical deep dive into polymorphic fields and how to query against them here:

This makes me sad

Alas, we are not allowed to create polymorphic relationship fields. And begrudgingly it makes sense why we aren’t allowed–the amount of overhead necessary to manage potentially many different related objects, related lists and reporting would be significant. That being said–it would be darn amazing if we could. It’s not all doom and gloom though–we can certainly leverage them.

2. JunctionIdList:

A specialized relationship field with the primary focus of simplifying working with Tasks and Events that are shared with multiple users (Shared Activities must be enabled). This reference field acts as a proxy for the standard join object that relates multiple Contacts to the Task or Event. Instead of having to manipulate the join object (named TaskWhoRelation for Task), we can instead manipulate the Task’s TaskWhoIds field—which in turn will automatically update the related TaskWhoRelation objects. From a programming perspective this is a more efficient way to manipulate Tasks as it reduces the number of calls to make updates.

Record Locking-it Matters!

In the previous post, we promised that we would dive into record locking. Wait. Why are we talking about record locking in a series that’s devoted to understanding Salesforce data relationships–why does it matter? It matters a great deal—especially if the org is large or complex. Record locks can apply to  any changed record and potentially impact any related records. 

First, let’s dive into what exactly is record locking.

Record locking is a way to prevent inconsistent data. At a high level it works by preventing a record from being updated when it is already being updated. These different update attempts can be performed by users or automated processes. Let’s say we have a scheduled job on Cases that changes a field used to categorize Case records based on its age. If this job ran while users were working Cases the likelihood of both processing that same record is very good and these changes could collide. To prevent inconsistent data, Salesforce gives exclusive access to the ‘first one in’ throwing errors for other parties preventing their changes.

Now let’s explore how record locks can also impact related records. If an edit occurs on the Opportunity object—not only is the Opportunity object locked—so is the related Account (Opportunity and Account records–while technically related through a lookup relationship on steroids–are tightly coupled due to potential roll-up as well as sharing re-calculations). Similarly, this applies also to Case and Contact objects (if either has an associated Account—that Account gets locked). Think about it why this matters: if we have a large support organization with lots of Cases it is very possible for two agents working different Cases for the same related Account running into issues.

When it comes to custom lookups and master-detail relationships there are record locking considerations.

  • Lookups: All we have to worry about is if the lookup is not set to clear the value of the relationship if the related record is deleted (a setting on the lookup field definition). If this field setting is not set—then the related parent record will be locked when the child record is either created, edited or deleted.
  • Master-detail: Whenever a child record is inserted, deleted or re-parented, the parent is locked. If there is a rollup field on the parent (reminder: master side of the relationship), the parent will always lock whenever the child is updated regardless if the fields being used in the rollup calculations have changed.

If you want to learn more about record locking behavior and the other scenarios check out these two resources: and

One User and One User Only, Please

What can we do to stop record lock errors? The best way is to only have one user in the org. Obviously having a single user defeats the purpose of having Salesforce and all the benefits it provides. (By the way, record locks are not unique to Salesforce—it applies to any database system that allows multiple user access.)

We can’t avoid the reality that more than one user (and/or process) can attempt to update the same record–there is no way to completely prevent it. What we really need to do is work to minimize the risk whenever possible (and feasible). And this is ongoing work, especially if an org is growing and changing.

Here are a few things to consider/try:

  • Run scheduled batch jobs after hours
  • If the org is 24/7 determine if batches can be set to process targeted records for regions that when run is ‘after hours’
  • Segment data so users are working on what’s relevant to them (consider leveraging record types for certain teams)
  • Consolidate workflows (less time the records are locked)
  • Reduce save times by consolidating code (less time the records are locked)

There are other techniques that can be considered and are outside the scope of this post, check out the plenty of resources online for more guidance.

Next in our series, we are shifting the discussion from standard and custom objects and their relationships to relating metadata through Custom Metadata Types in “Part 4: Custom Metadata Type Relationships: Yes, it’s a Thing“. Yes, we can create relationships between certain kinds of metadata. 

 View the entire 5-part Salesforce Data Relationships series here.

Series NavigationPart 2: Exploring Salesforce Relationship WorkhorsesPart 4: Custom Metadata Type Relationships: Yes, It’s a Thing
Mark Budzyn
Mark Budzyn
Mark Budzyn
Mark is IC's Manager of Professional Services. He is big into collaboration and motivated by taking on business challenges and wrestling them to the ground.